From 200fbe924466720bd2a8c5eb05b05d67b0a2414c Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Thu, 14 Mar 2013 15:42:19 +0100 Subject: Added support for ENEA OSE This port has support for both non-smp and smp. It contains a new way to do io checking in which erts_poll_wait receives the payload of the polled entity. This has implications for all linked-in drivers. --- erts/emulator/drivers/common/efile_drv.c | 3 + erts/emulator/drivers/common/inet_drv.c | 110 ++- erts/emulator/drivers/ose/ose_efile.c | 1090 ++++++++++++++++++++++++++++++ 3 files changed, 1202 insertions(+), 1 deletion(-) create mode 100644 erts/emulator/drivers/ose/ose_efile.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index e040864d24..fbd72c6c1b 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -373,6 +373,9 @@ struct erl_drv_entry efile_driver_entry = { #else NULL #endif /* HAVE_SENDFILE */ +#ifdef __OSE__ + ,NULL +#endif }; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 4a861b121c..357a4b7bcb 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -121,6 +121,10 @@ typedef unsigned long long llu_t; #undef WANT_NONBLOCKING #include "sys.h" +#ifdef __OSE__ +#include "inet.h" +#endif + #undef EWOULDBLOCK #undef ETIMEDOUT @@ -289,7 +293,111 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); static unsigned long zero_value = 0; static unsigned long one_value = 1; -#else /* #ifdef __WIN32__ */ +#elif defined (__OSE__) +#include "sys/socket.h" +#include "sys/uio.h" +#include "sfk/sys/sfk_uio.h" +#include "netinet/in.h" +#include "netinet/tcp.h" +#include "netdb.h" + +ssize_t writev(int fd, const struct iovec *iov, int iovcnt) +{ + return 0; +} + +#define INVALID_SOCKET -1 +#define INVALID_EVENT -1 +#define SOCKET_ERROR -1 + +#define SOCKET int +#define HANDLE long int +#define FD_READ ERL_DRV_READ +#define FD_WRITE ERL_DRV_WRITE +#define FD_CLOSE 0 +#define FD_CONNECT ERL_DRV_WRITE +#define FD_ACCEPT ERL_DRV_READ + +#define sock_connect(s, addr, len) connect((s), (addr), (len)) +#define sock_listen(s, b) listen((s), (b)) +#define sock_bind(s, addr, len) bind((s), (addr), (len)) +#define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) +#define sock_setopt(s,t,n,v,l) setsockopt((s),(t),(n),(v),(l)) +#define sock_name(s, addr, len) getsockname((s), (addr), (len)) +#define sock_peer(s, addr, len) getpeername((s), (addr), (len)) +#define sock_ntohs(x) ntohs((x)) +#define sock_ntohl(x) ntohl((x)) +#define sock_htons(x) htons((x)) +#define sock_htonl(x) htonl((x)) + +#define sock_accept(s, addr, len) accept((s), (addr), (len)) +#define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) +#define sock_sendto(s,buf,blen,flag,addr,alen) \ + sendto((s),(buf),(blen),(flag),(addr),(alen)) +#define sock_sendv(s, vec, size, np, flag) \ + (*(np) = writev((s), (struct iovec*)(vec), (size))) +#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) + +#define sock_open(af, type, proto) socket((af), (type), (proto)) +#define sock_close(s) close((s)) +#define sock_shutdown(s, how) shutdown((s), (how)) + +#define sock_hostname(buf, len) gethostname((buf), (len)) +#define sock_getservbyname(name,proto) getservbyname((name), (proto)) +#define sock_getservbyport(port,proto) getservbyport((port), (proto)) + +#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) +#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ + recvfrom((s),(buf),(blen),(flag),(addr),(alen)) +#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) + +#define sock_errno() errno +#define sock_create_event(d) ((d)->s) /* return file descriptor */ +#define sock_close_event(e) /* do nothing */ + +#define inet_driver_select(port, e, mode, on) \ + driver_select(port, e, mode | (on?ERL_DRV_USE:0), on) + +#define sock_select(d, flags, onoff) do { \ + ASSERT(!(d)->is_ignored); \ + (d)->event_mask = (onoff) ? \ + ((d)->event_mask | (flags)) : \ + ((d)->event_mask & ~(flags)); \ + DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ + (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ + inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ + } while(0) + +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif +#include "sys.h" + +typedef unsigned long u_long; +#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) + +#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) + +#else /* !__OSE__ && !__WIN32__ */ #include #ifdef NETDB_H_NEEDS_IN_H diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c new file mode 100644 index 0000000000..8cd34a7bb0 --- /dev/null +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -0,0 +1,1090 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1997-2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Purpose: Provides file and directory operations for OSE. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#if defined(HAVE_POSIX_FALLOCATE) && !defined(__sun) && !defined(__sun__) +#define _XOPEN_SOURCE 600 +#endif +#if !defined(_GNU_SOURCE) && defined(HAVE_LINUX_FALLOC_H) +#define _GNU_SOURCE +#endif +#include "sys.h" +#include "erl_driver.h" +#include "erl_efile.h" +/*#include */ +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_UIO_H +#include +#include +#endif +#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) +#include +#endif + +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +#define DARWIN 1 +#endif + +#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) +#include +#endif + +#ifdef HAVE_LINUX_FALLOC_H +#include +#endif + +#ifdef SUNOS4 +# define getcwd(buf, size) getwd(buf) +#endif + +#ifdef __OSE__ +#include "sys/stat.h" +#include "dirent.h" +#endif + +/* Find a definition of MAXIOV, that is used in the code later. */ +#if defined IOV_MAX +#define MAXIOV IOV_MAX +#elif defined UIO_MAXIOV +#define MAXIOV UIO_MAXIOV +#else +#define MAXIOV 16 +#endif + + +/* + * Macros for testing file types. + */ + +#define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR) +#define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG) +#define ISDEV(st) \ + (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) +#define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK) +#ifdef NO_UMASK +#define FILE_MODE 0644 +#define DIR_MODE 0755 +#else +#define FILE_MODE 0666 +#define DIR_MODE 0777 +#endif + +#define IS_DOT_OR_DOTDOT(s) \ + (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) + +static int check_error(int result, Efile_error* errInfo); + +static int +check_error(int result, Efile_error *errInfo) +{ + if (result < 0) { + errInfo->posix_errno = errInfo->os_errno = errno; + return 0; + } + return 1; +} + +int +efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to create. */ +{ +#ifdef NO_MKDIR_MODE + return check_error(mkdir(name), errInfo); +#else + return check_error(mkdir(name, DIR_MODE), errInfo); +#endif +} + +int +efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to delete. */ +{ + if (rmdir(name) == 0) { + return 1; + } + if (errno == ENOTEMPTY) { + errno = EEXIST; + } + if (errno == EEXIST) { + int saved_errno = errno; + struct stat file_stat; + struct stat cwd_stat; + + /* + * The error code might be wrong if this is the current directory. + */ + + if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && + file_stat.st_ino == cwd_stat.st_ino && + file_stat.st_dev == cwd_stat.st_dev) { + saved_errno = EINVAL; + } + errno = saved_errno; + } + return check_error(-1, errInfo); +} + +int +efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of file to delete. */ +{ + if (unlink(name) == 0) { + return 1; + } + if (errno == EISDIR) { /* Linux sets the wrong error code. */ + errno = EPERM; + } + return check_error(-1, errInfo); +} + +/* + *--------------------------------------------------------------------------- + * + * Changes the name of an existing file or directory, from src to dst. + * If src and dst refer to the same file or directory, does nothing + * and returns success. Otherwise if dst already exists, it will be + * deleted and replaced by src subject to the following conditions: + * If src is a directory, dst may be an empty directory. + * If src is a file, dst may be a file. + * In any other situation where dst already exists, the rename will + * fail. + * + * Results: + * If the directory was successfully created, returns 1. + * Otherwise the return value is 0 and errno is set to + * indicate the error. Some possible values for errno are: + * + * EACCES: src or dst parent directory can't be read and/or written. + * EEXIST: dst is a non-empty directory. + * EINVAL: src is a root directory or dst is a subdirectory of src. + * EISDIR: dst is a directory, but src is not. + * ENOENT: src doesn't exist, or src or dst is "". + * ENOTDIR: src is a directory, but dst is not. + * EXDEV: src and dst are on different filesystems. + * + * Side effects: + * The implementation of rename may allow cross-filesystem renames, + * but the caller should be prepared to emulate it with copy and + * delete if errno is EXDEV. + * + *--------------------------------------------------------------------------- + */ + +int +efile_rename(Efile_error* errInfo, /* Where to return error codes. */ + char* src, /* Original name. */ + char* dst) /* New name. */ +{ + if (rename(src, dst) == 0) { + return 1; + } + if (errno == ENOTEMPTY) { + errno = EEXIST; + } +#if defined (sparc) + /* + * SunOS 4.1.4 reports overwriting a non-empty directory with a + * directory as EINVAL instead of EEXIST (first rule out the correct + * EINVAL result code for moving a directory into itself). Must be + * conditionally compiled because realpath() is only defined on SunOS. + */ + + if (errno == EINVAL) { + char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN]; + DIR *dirPtr; + struct dirent *dirEntPtr; + +#ifdef PURIFY + memset(srcPath, '\0', sizeof(srcPath)); + memset(dstPath, '\0', sizeof(dstPath)); +#endif + + if ((realpath(src, srcPath) != NULL) + && (realpath(dst, dstPath) != NULL) + && (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) { + dirPtr = opendir(dst); + if (dirPtr != NULL) { + while ((dirEntPtr = readdir(dirPtr)) != NULL) { + if ((strcmp(dirEntPtr->d_name, ".") != 0) && + (strcmp(dirEntPtr->d_name, "..") != 0)) { + errno = EEXIST; + closedir(dirPtr); + return check_error(-1, errInfo); + } + } + closedir(dirPtr); + } + } + errno = EINVAL; + } +#endif /* sparc */ + + if (strcmp(src, "/") == 0) { + /* + * Alpha reports renaming / as EBUSY and Linux reports it as EACCES, + * instead of EINVAL. + */ + + errno = EINVAL; + } + + /* + * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a + * file across filesystems and the parent directory of that file is + * not writable. Most other systems return EXDEV. Does nothing to + * correct this behavior. + */ + + return check_error(-1, errInfo); +} + +int +efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to make current. */ +{ + return check_error(chdir(name), errInfo); +} + + +int +efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ + int drive, /* 0 - current, 1 - A, 2 - B etc. */ + char* buffer, /* Where to return the current + directory. */ + size_t size) /* Size of buffer. */ +{ + if (drive == 0) { + if (getcwd(buffer, size) == NULL) + return check_error(-1, errInfo); + +#ifdef SIMSPARCSOLARIS + /* We get "host:" prepended to the dirname - remove!. */ + { + int i = 0; + int j = 0; + while ((buffer[i] != ':') && (buffer[i] != '\0')) i++; + if (buffer[i] == ':') { + i++; + while ((buffer[j++] = buffer[i++]) != '\0'); + } + } +#endif + return 1; + } + + /* + * Drives other than 0 is not supported on Unix. + */ + + errno = ENOTSUP; + return check_error(-1, errInfo); +} + +int +efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory + handle of + open directory.*/ + char* buffer, /* Pointer to buffer for + one filename. */ + size_t *size) /* in-out Size of buffer, length + of name. */ +{ + DIR *dp; /* Pointer to directory structure. */ + struct dirent* dirp; /* Pointer to directory entry. */ + + /* + * If this is the first call, we must open the directory. + */ + + if (*p_dir_handle == NULL) { + dp = opendir(name); + if (dp == NULL) + return check_error(-1, errInfo); + *p_dir_handle = (EFILE_DIR_HANDLE) dp; + } + + /* + * Retrieve the name of the next file using the directory handle. + */ + + dp = *((DIR **)((void *)p_dir_handle)); + for (;;) { + dirp = readdir(dp); + if (dirp == NULL) { + closedir(dp); + return 0; + } + if (IS_DOT_OR_DOTDOT(dirp->d_name)) + continue; + buffer[0] = '\0'; + strncat(buffer, dirp->d_name, (*size)-1); + *size = strlen(dirp->d_name); + return 1; + } +} + +int +efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + int flags, /* Flags to user for opening. */ + int* pfd, /* Where to store the file + descriptor. */ + Sint64 *pSize) /* Where to store the size of the + file. */ +{ + struct stat statbuf; + int fd; + int mode; /* Open mode. */ + + if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { + /* + * For UNIX only, here is some ugly code to allow + * /dev/null to be opened as a file. + * + * Assumption: The i-node number for /dev/null cannot be zero. + */ + static ino_t dev_null_ino = 0; + + if (dev_null_ino == 0) { + struct stat nullstatbuf; + + if (stat("/dev/null", &nullstatbuf) >= 0) { + dev_null_ino = nullstatbuf.st_ino; + } + } + if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) { + errno = EISDIR; + return check_error(-1, errInfo); + } + } + + switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { + case EFILE_MODE_READ: + mode = O_RDONLY; + break; + case EFILE_MODE_WRITE: + if (flags & EFILE_NO_TRUNCATE) + mode = O_WRONLY | O_CREAT; + else + mode = O_WRONLY | O_CREAT | O_TRUNC; + break; + case EFILE_MODE_READ_WRITE: + mode = O_RDWR | O_CREAT; + break; + default: + errno = EINVAL; + return check_error(-1, errInfo); + } + + + if (flags & EFILE_MODE_APPEND) { + mode &= ~O_TRUNC; + mode |= O_APPEND; + } + + if (flags & EFILE_MODE_EXCL) { + mode |= O_EXCL; + } + + fd = open(name, mode, FILE_MODE); + + if (!check_error(fd, errInfo)) + return 0; + + *pfd = fd; + if (pSize) { + *pSize = statbuf.st_size; + } + return 1; +} + +int +efile_may_openfile(Efile_error* errInfo, char *name) { + struct stat statbuf; /* Information about the file */ + int result; + + result = stat(name, &statbuf); + if (!check_error(result, errInfo)) + return 0; + if (!ISREG(statbuf)) { + errno = EISDIR; + return check_error(-1, errInfo); + } + return 1; +} + +void +efile_closefile(int fd) +{ + close(fd); +} + +int +efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ + int fd) /* File descriptor for file to sync data. */ +{ +#ifdef HAVE_FDATASYNC + return check_error(fdatasync(fd), errInfo); +#else + return efile_fsync(errInfo, fd); +#endif +} + +int +efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ + int fd) /* File descriptor for file to sync. */ +{ +#ifdef NO_FSYNC + undefined fsync /* XXX: Really? */ +#else +#if defined(DARWIN) && defined(F_FULLFSYNC) + return check_error(fcntl(fd, F_FULLFSYNC), errInfo); +#else + return check_error(fsync(fd), errInfo); +#endif /* DARWIN */ +#endif /* NO_FSYNC */ +} + +int +efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, + char* name, int info_for_link) +{ + struct stat statbuf; /* Information about the file */ + int result; + + if (info_for_link) { +#ifndef __OSE__ + result = lstat(name, &statbuf); +#else + result = stat(name, &statbuf); +#endif + } else { + result = stat(name, &statbuf); + } + if (!check_error(result, errInfo)) { + return 0; + } + +#if SIZEOF_OFF_T == 4 + pInfo->size_high = 0; +#else + pInfo->size_high = (Uint32)(statbuf.st_size >> 32); +#endif + pInfo->size_low = (Uint32)statbuf.st_size; + +#ifdef NO_ACCESS + /* Just look at read/write access for owner. */ + + pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1; + +#else + pInfo->access = FA_NONE; + if (access(name, R_OK) == 0) + pInfo->access |= FA_READ; + if (access(name, W_OK) == 0) + pInfo->access |= FA_WRITE; + +#endif + + if (ISDEV(statbuf)) + pInfo->type = FT_DEVICE; + else if (ISDIR(statbuf)) + pInfo->type = FT_DIRECTORY; + else if (ISREG(statbuf)) + pInfo->type = FT_REGULAR; + else if (ISLNK(statbuf)) + pInfo->type = FT_SYMLINK; + else + pInfo->type = FT_OTHER; + + pInfo->accessTime = statbuf.st_atime; + pInfo->modifyTime = statbuf.st_mtime; + pInfo->cTime = statbuf.st_ctime; + + pInfo->mode = statbuf.st_mode; + pInfo->links = statbuf.st_nlink; + pInfo->major_device = statbuf.st_dev; +#ifndef __OSE__ + pInfo->minor_device = statbuf.st_rdev; +#endif + pInfo->inode = statbuf.st_ino; + pInfo->uid = statbuf.st_uid; + pInfo->gid = statbuf.st_gid; + + return 1; +} + +int +efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) +{ +#ifndef __OSE__ + struct utimbuf tval; +#endif + + /* + * On some systems chown will always fail for a non-root user unless + * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as + * you don't try to chown a file to someone besides youself. + */ +#ifndef __OSE__ + if (chown(name, pInfo->uid, pInfo->gid) && errno != EPERM) { + return check_error(-1, errInfo); + } +#endif + + if (pInfo->mode != -1) { + mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | + S_IRWXU | S_IRWXG | S_IRWXO); + if (chmod(name, newMode)) { + newMode &= ~(S_ISUID | S_ISGID); + if (chmod(name, newMode)) { + return check_error(-1, errInfo); + } + } + } + +#ifndef __OSE__ + tval.actime = pInfo->accessTime; + tval.modtime = pInfo->modifyTime; + + return check_error(utime(name, &tval), errInfo); +#else + return 1; +#endif +} + + +int +efile_write(Efile_error* errInfo, /* Where to return error codes. */ + int flags, /* Flags given when file was + opened. */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count) /* Number of bytes to write. */ +{ + ssize_t written; /* Bytes written in last operation. */ + + while (count > 0) { + if ((written = write(fd, buf, count)) < 0) { + if (errno != EINTR) + return check_error(-1, errInfo); + else + written = 0; + } + ASSERT(written <= count); + buf += written; + count -= written; + } + return 1; +} + +int +efile_writev(Efile_error* errInfo, /* Where to return error codes */ + int flags, /* Flags given when file was + * opened */ + int fd, /* File descriptor to write to */ + SysIOVec* iov, /* Vector of buffer structs. + * The structs may be changed i.e. + * due to incomplete writes */ + int iovcnt) /* Number of structs in vector */ +{ + int cnt = 0; /* Buffers so far written */ + + ASSERT(iovcnt >= 0); + + while (cnt < iovcnt) { + if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { + /* Empty buffer - skip */ + cnt++; + } else { /* Non-empty buffer */ + ssize_t w; /* Bytes written in this call */ +#ifdef HAVE_WRITEV + int b = iovcnt - cnt; /* Buffers to write */ + /* Use as many buffers as MAXIOV allows */ + if (b > MAXIOV) + b = MAXIOV; + if (b > 1) { + do { + w = writev(fd, &iov[cnt], b); + } while (w < 0 && errno == EINTR); + } else + /* Degenerated io vector - use regular write */ +#endif + { + do { + w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + } while (w < 0 && errno == EINTR); + ASSERT(w <= iov[cnt].iov_len || w == -1); + } + if (w < 0) return check_error(-1, errInfo); + /* Move forward to next buffer to write */ + for (; cnt < iovcnt && w > 0; cnt++) { + if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { + if (w < iov[cnt].iov_len) { + /* Adjust the buffer for next write */ + iov[cnt].iov_len -= w; + iov[cnt].iov_base += w; + w = 0; + break; + } else { + w -= iov[cnt].iov_len; + } + } + } + ASSERT(w == 0); + } /* else Non-empty buffer */ + } /* while (cnt< iovcnt) */ + return 1; +} + +int +efile_read(Efile_error* errInfo, /* Where to return error codes. */ + int flags, /* Flags given when file was opened. */ + int fd, /* File descriptor to read from. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return number of + bytes read. */ +{ + ssize_t n; + + for (;;) { + if ((n = read(fd, buf, count)) >= 0) + break; + else if (errno != EINTR) + return check_error(-1, errInfo); + } + *pBytesRead = (size_t) n; + return 1; +} + + +/* pread() and pwrite() */ +/* Some unix systems, notably Solaris has these syscalls */ +/* It is especially nice for i.e. the dets module to have support */ +/* for this, even if the underlying OS dosn't support it, it is */ +/* reasonably easy to work around by first calling seek, and then */ +/* calling read(). */ +/* This later strategy however changes the file pointer, which pread() */ +/* does not do. We choose to ignore this and say that the location */ +/* of the file pointer is undefined after a call to any of the p functions*/ + + +int +efile_pread(Efile_error* errInfo, /* Where to return error codes. */ + int fd, /* File descriptor to read from. */ + Sint64 offset, /* Offset in bytes from BOF. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return + number of bytes read. */ +{ +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + ssize_t n; + off_t off = (off_t) offset; + if (off != offset) { + errno = EINVAL; + return check_error(-1, errInfo); + } + for (;;) { + if ((n = pread(fd, buf, count, offset)) >= 0) + break; + else if (errno != EINTR) + return check_error(-1, errInfo); + } + *pBytesRead = (size_t) n; + return 1; +#else + { + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + if (res) { + return efile_read(errInfo, 0, fd, buf, count, pBytesRead); + } else { + return res; + } + } +#endif +} + + + +int +efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count, /* Number of bytes to write. */ + Sint64 offset) /* where to write it */ +{ +#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) + ssize_t written; /* Bytes written in last operation. */ + off_t off = (off_t) offset; + if (off != offset) { + errno = EINVAL; + return check_error(-1, errInfo); + } + + while (count > 0) { + if ((written = pwrite(fd, buf, count, offset)) < 0) { + if (errno != EINTR) + return check_error(-1, errInfo); + else + written = 0; + } + ASSERT(written <= count); + buf += written; + count -= written; + offset += written; + } + return 1; +#else /* For unix systems that don't support pread() and pwrite() */ + { + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + + if (res) { + return efile_write(errInfo, 0, fd, buf, count); + } else { + return res; + } + } +#endif +} + + +int +efile_seek(Efile_error* errInfo, /* Where to return error codes. */ + int fd, /* File descriptor to do the seek on. */ + Sint64 offset, /* Offset in bytes from the given + origin. */ + int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, + SEEK_END). */ + Sint64 *new_location) /* Resulting new location in file. */ +{ + off_t off, result; + + switch (origin) { + case EFILE_SEEK_SET: origin = SEEK_SET; break; + case EFILE_SEEK_CUR: origin = SEEK_CUR; break; + case EFILE_SEEK_END: origin = SEEK_END; break; + default: + errno = EINVAL; + return check_error(-1, errInfo); + } + off = (off_t) offset; + if (off != offset) { + errno = EINVAL; + return check_error(-1, errInfo); + } + + errno = 0; + result = lseek(fd, off, origin); + + /* + * Note that the man page for lseek (on SunOs 5) says: + * + * "if fildes is a remote file descriptor and offset is + * negative, lseek() returns the file pointer even if it is + * negative." + */ + + if (result < 0 && errno == 0) + errno = EINVAL; + if (result < 0) + return check_error(-1, errInfo); + if (new_location) { + *new_location = result; + } + return 1; +} + + +int +efile_truncate_file(Efile_error* errInfo, int *fd, int flags) +{ +#ifndef NO_FTRUNCATE + off_t offset; + + return check_error((offset = lseek(*fd, 0, 1)) >= 0 && + ftruncate(*fd, offset) == 0 ? 1 : -1, + errInfo); +#else + return 1; +#endif +} + +int +efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) +{ +#ifndef __OSE__ + int len; + ASSERT(size > 0); + len = readlink(name, buffer, size-1); + if (len == -1) { + return check_error(-1, errInfo); + } + buffer[len] = '\0'; + return 1; +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} + +int +efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) +{ + errno = ENOTSUP; + return check_error(-1, errInfo); +} + +int +efile_link(Efile_error* errInfo, char* old, char* new) +{ +#ifndef __OSE__ + return check_error(link(old, new), errInfo); +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} + +int +efile_symlink(Efile_error* errInfo, char* old, char* new) +{ +#ifndef __OSE__ + return check_error(symlink(old, new), errInfo); +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} + +int +efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, + Sint64 length, int advise) +{ +#ifdef HAVE_POSIX_FADVISE + return check_error(posix_fadvise(fd, offset, length, advise), errInfo); +#else + return check_error(0, errInfo); +#endif +} + +#ifdef HAVE_SENDFILE +/* For some reason the maximum size_t cannot be used as the max size + 3GB seems to work on all platforms */ +#define SENDFILE_CHUNK_SIZE ((1UL << 30) -1) + +/* + * sendfile: The implementation of the sendfile system call varies + * a lot on different *nix platforms so to make the api similar in all + * we have to emulate some things in linux and play with variables on + * bsd/darwin. + * + * All of the calls will split a command which tries to send more than + * SENDFILE_CHUNK_SIZE of data at once. + * + * On platforms where *nbytes of 0 does not mean the entire file, this is + * simulated. + * + * It could be possible to implement header/trailer in sendfile. Though + * you would have to emulate it in linux and on BSD/Darwin some complex + * calculations have to be made when using a non blocking socket to figure + * out how much of the header/file/trailer was sent in each command. + * + * The semantics of the API is this: + * Return value: 1 if all data was sent and the function does not need to + * be called again. 0 if an error occures OR if there is more data which + * has to be sent (EAGAIN or EINTR will be set appropriately) + * + * The amount of data written in a call is returned through nbytes. + * + */ + +int +efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, + off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl* hdtl) +{ + Uint64 written = 0; +#if defined(__linux__) + ssize_t retval; + do { + /* check if *nbytes is 0 or greater than chunk size */ + if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) + retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE); + else + retval = sendfile(out_fd, in_fd, offset, *nbytes); + if (retval > 0) { + written += retval; + *nbytes -= retval; + } + } while (retval == SENDFILE_CHUNK_SIZE); + if (written != 0) { + /* -1 is not returned by the linux API so we have to simulate it */ + retval = -1; + errno = EAGAIN; + } +#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) + ssize_t retval; + size_t len; + sendfilevec_t fdrec; + fdrec.sfv_fd = in_fd; + fdrec.sfv_flag = 0; + do { + fdrec.sfv_off = *offset; + len = 0; + /* check if *nbytes is 0 or greater than chunk size */ + if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) + fdrec.sfv_len = SENDFILE_CHUNK_SIZE; + else + fdrec.sfv_len = *nbytes; + retval = sendfilev(out_fd, &fdrec, 1, &len); + + /* Sometimes sendfilev can return -1 and still send data. + When that happens we just pretend that no error happend. */ + if (retval != -1 || errno == EAGAIN || errno == EINTR || + len != 0) { + *offset += len; + *nbytes -= len; + written += len; + if (errno != EAGAIN && errno != EINTR && len != 0) + retval = len; + } + } while (len == SENDFILE_CHUNK_SIZE); +#elif defined(DARWIN) + int retval; + off_t len; + do { + /* check if *nbytes is 0 or greater than chunk size */ + if(*nbytes > SENDFILE_CHUNK_SIZE) + len = SENDFILE_CHUNK_SIZE; + else + len = *nbytes; + retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0); + if (retval != -1 || errno == EAGAIN || errno == EINTR) { + *offset += len; + *nbytes -= len; + written += len; + } + } while (len == SENDFILE_CHUNK_SIZE); +#elif defined(__FreeBSD__) || defined(__DragonFly__) + off_t len; + int retval; + do { + if (*nbytes > SENDFILE_CHUNK_SIZE) + retval = sendfile(in_fd, out_fd, *offset, SENDFILE_CHUNK_SIZE, + NULL, &len, 0); + else + retval = sendfile(in_fd, out_fd, *offset, *nbytes, NULL, &len, 0); + if (retval != -1 || errno == EAGAIN || errno == EINTR) { + *offset += len; + *nbytes -= len; + written += len; + } + } while(len == SENDFILE_CHUNK_SIZE); +#endif + *nbytes = written; + return check_error(retval, errInfo); +} +#endif /* HAVE_SENDFILE */ + +#ifdef HAVE_POSIX_FALLOCATE +static int +call_posix_fallocate(int fd, Sint64 offset, Sint64 length) +{ + int ret; + + /* + * On Linux and Solaris for example, posix_fallocate() returns + * a positive error number on error and it does not set errno. + * On FreeBSD however (9.0 at least), it returns -1 on error + * and it sets errno. + */ + do { + ret = posix_fallocate(fd, (off_t) offset, (off_t) length); + if (ret > 0) { + errno = ret; + ret = -1; + } + } while (ret != 0 && errno == EINTR); + + return ret; +} +#endif /* HAVE_POSIX_FALLOCATE */ + +int +efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) +{ +#if defined HAVE_FALLOCATE + /* Linux specific, more efficient than posix_fallocate. */ + int ret; + + do { + ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, (off_t) offset, (off_t) length); + } while (ret != 0 && errno == EINTR); + +#if defined HAVE_POSIX_FALLOCATE + /* Fallback to posix_fallocate if available. */ + if (ret != 0) { + ret = call_posix_fallocate(fd, offset, length); + } +#endif + + return check_error(ret, errInfo); +#elif defined F_PREALLOCATE + /* Mac OS X specific, equivalent to posix_fallocate. */ + int ret; + fstore_t fs; + + memset(&fs, 0, sizeof(fs)); + fs.fst_flags = F_ALLOCATECONTIG; + fs.fst_posmode = F_VOLPOSMODE; + fs.fst_offset = (off_t) offset; + fs.fst_length = (off_t) length; + + ret = fcntl(fd, F_PREALLOCATE, &fs); + + if (-1 == ret) { + fs.fst_flags = F_ALLOCATEALL; + ret = fcntl(fd, F_PREALLOCATE, &fs); + +#if defined HAVE_POSIX_FALLOCATE + /* Fallback to posix_fallocate if available. */ + if (-1 == ret) { + ret = call_posix_fallocate(fd, offset, length); + } +#endif + } + + return check_error(ret, errInfo); +#elif defined HAVE_POSIX_FALLOCATE + /* Other Unixes, use posix_fallocate if available. */ + return check_error(call_posix_fallocate(fd, offset, length), errInfo); +#else + errno = ENOTSUP; + return check_error(-1, errInfo); +#endif +} -- cgit v1.2.3 From eed38c1bb1a12015377d30e9ceff9525e050850e Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Tue, 3 Sep 2013 11:48:00 +0200 Subject: ose: Convert EFILE_SEEK to unistd seek for gzio This is needed because OSE does not have the same integers as unix/win32 for SEEK_ST and friends. --- erts/emulator/drivers/common/gzio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index 653f3954b1..9a9e297fca 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -20,6 +20,7 @@ #endif #include #include "erl_driver.h" +#include "erl_efile.h" #include "sys.h" #ifdef __WIN32__ @@ -597,6 +598,15 @@ erts_gzseek(ErtsGzFile file, int offset, int whence) int pos; gz_stream* s = (gz_stream *) file; + switch (whence) { + case EFILE_SEEK_SET: whence = SEEK_SET; break; + case EFILE_SEEK_CUR: whence = SEEK_CUR; break; + case EFILE_SEEK_END: whence = SEEK_END; break; + default: + errno = EINVAL; + return -1; + } + if (s == NULL) { errno = EINVAL; return -1; -- cgit v1.2.3 From e2d4b774f4141bdf530696c0abe3704655ed3aa3 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Tue, 15 Oct 2013 16:59:38 +0200 Subject: ose: lseek() to use SEEK_CUR This is needed because OSE does not use 1 for SEEK_CUR --- erts/emulator/drivers/ose/ose_efile.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 8cd34a7bb0..fc255e11ef 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -33,8 +33,10 @@ #include "erl_efile.h" /*#include */ #ifdef HAVE_UNISTD_H +#ifndef __OSE__ #include #endif +#endif #ifdef HAVE_SYS_UIO_H #include #include @@ -60,8 +62,11 @@ #endif #ifdef __OSE__ +#include "unistd.h" #include "sys/stat.h" #include "dirent.h" +#include "sys/time.h" +#include "time.h" #endif /* Find a definition of MAXIOV, that is used in the code later. */ @@ -826,10 +831,8 @@ efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { #ifndef NO_FTRUNCATE off_t offset; - - return check_error((offset = lseek(*fd, 0, 1)) >= 0 && - ftruncate(*fd, offset) == 0 ? 1 : -1, - errInfo); + return check_error((offset = lseek(*fd, 0, SEEK_CUR)) >= 0 && + ftruncate(*fd, offset) == 0 ? 1 : -1, errInfo); #else return 1; #endif -- cgit v1.2.3 From fa3dd14716b2a7ad0c223ebacd2ffc6ecf6437e6 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 30 Sep 2013 15:07:49 +0200 Subject: ose: Add module that allows interaction with any OSE process The interface of this module is made to be as generic as possible in order for other IPC mechanisms to mimic it and allow porting of code between different os:es. --- erts/emulator/drivers/ose/ose_signal_drv.c | 884 +++++++++++++++++++++++++++++ 1 file changed, 884 insertions(+) create mode 100644 erts/emulator/drivers/ose/ose_signal_drv.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c new file mode 100644 index 0000000000..acf09f748e --- /dev/null +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -0,0 +1,884 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2013-2013. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "errno.h" +#include "stdio.h" +#include "string.h" +#include "stddef.h" + +#include "sys.h" +#include "erl_driver.h" +#include "ose.h" +#include "ose_spi/ose_spi.h" + +#define DEBUG_ATTACH 0 +#define DEBUG_HUNT 0 +#define DEBUG_SEND 0 +#define DEBUG_LISTEN 0 + +#if 0 +#define DEBUGP(FMT,...) printf(FMT, __VA_ARGS__) +#else +#define DEBUGP(FMT,...) +#endif + +#if DEBUG_ATTACH +#define DEBUGP_ATTACH(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_ATTACH(...) +#endif + +#if DEBUG_HUNT +#define DEBUGP_HUNT(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_HUNT(...) +#endif + +#if DEBUG_LISTEN +#define DEBUGP_LISTEN(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_LISTEN(...) +#endif + +#if DEBUG_SEND +#define DEBUGP_SEND(...) DEBUGP( __VA_ARGS__) +#else +#define DEBUGP_SEND(...) +#endif + + +#define DRIVER_NAME "ose_signal_drv" +#define GET_SPID 1 +#define GET_NAME 2 +#define HUNT 100 +#define DEHUNT 101 +#define ATTACH 102 +#define DETACH 103 +#define SEND 104 +#define SEND_W_S 105 +#define LISTEN 106 +#define OPEN 200 + +#define REF_SEGMENT_SIZE 8 + +struct async { + SIGSELECT signo; + ErlDrvTermData port; + ErlDrvTermData proc; + PROCESS spid; + PROCESS target; + Uint32 ref; +}; + +/** + * OSE signals + **/ +union SIGNAL { + SIGSELECT signo; + struct async async; +}; + +/** + * The driver's context + **/ +typedef struct _driver_context { + ErlDrvPort port; + PROCESS spid; + ErlDrvEvent perm_events[2]; + ErlDrvEvent *events; + Uint32 event_cnt; + Uint32 ref; + Uint32 *outstanding_refs; + Uint32 outstanding_refs_max; + Uint32 outstanding_refs_cnt; +} driver_context_t; + +/** + * Global variables + **/ +static ErlDrvTermData a_ok; +static ErlDrvTermData a_error; +static ErlDrvTermData a_enomem; +static ErlDrvTermData a_enoent; +static ErlDrvTermData a_badarg; +static ErlDrvTermData a_mailbox_up; +static ErlDrvTermData a_mailbox_down; +static ErlDrvTermData a_ose_drv_reply; +static ErlDrvTermData a_message; +static PROCESS proxy_proc; + + +/** + * Serialize/unserialize unsigned 32-bit values + **/ +static char *put_u32(unsigned int value, char *ptr) { + *ptr++ = (value & 0xff000000) >> 24; + *ptr++ = (value & 0x00ff0000) >> 16; + *ptr++ = (value & 0x0000ff00) >> 8; + *ptr++ = (value & 0xff); + + return ptr; +} + +static unsigned int get_u32(char *ptr) { + unsigned int result = 0; + result += (ptr[0] & 0xff) << 24; + result += (ptr[1] & 0xff) << 16; + result += (ptr[2] & 0xff) << 8; + result += (ptr[3] & 0xff); + + return result; +} + + +/* Stolen from efile_drv.c */ + +/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ +#define EV_CHAR_P(ev, p, q) \ + (((char *)(ev)->iov[(q)].iov_base) + (p)) + +/* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */ +#define EV_GET_CHAR(ev, p, pp, qp) ev_get_char(ev, p ,pp, qp) +static int +ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { + if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) { + *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); + if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+1; + else { + (*(qp))++; + *pp = 0; + } + return !0; + } + return 0; +} + +/* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/ +#define EV_UINT32(ev, p, q) \ + ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) + +/* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ +#define EV_GET_UINT32(ev, p, pp, qp) ev_get_uint32(ev,(Uint32*)(p),pp,qp) +static int +ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { + if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) { + *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) + | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) + | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) + | (EV_UINT32(ev, *(pp)+3, *(qp))); + if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) + *(pp) = *(pp)+4; + else { + (*(qp))++; + *pp = 0; + } + return !0; + } + return 0; +} + +/** + * Convinience macros + **/ +#define send_response(port,output) erl_drv_send_term(driver_mk_port(port),\ + driver_caller(port), output, sizeof(output) / sizeof(output[0])); + +void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off); +void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off) { + int i; + memcpy(dest,ev->iov[ind].iov_base+off,ev->iov[ind].iov_len-off); + for (i = ind+1; i < ev->vsize; i++) + memcpy(dest,ev->iov[i].iov_base,ev->iov[i].iov_len); +} + +/** + * Reference handling + **/ + +static int add_reference(driver_context_t *ctxt, Uint32 ref) { + + /* + * Premature optimizations may be evil, but they sure are fun. + */ + + if (ctxt->outstanding_refs == NULL) { + /* First ref to be ignored */ + ctxt->outstanding_refs = driver_alloc(REF_SEGMENT_SIZE*sizeof(Uint32)); + if (!ctxt->outstanding_refs) + return 1; + + memset(ctxt->outstanding_refs,0,REF_SEGMENT_SIZE*sizeof(Uint32)); + ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; + ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; + } else if (ctxt->outstanding_refs_cnt == ctxt->outstanding_refs_max) { + /* Expand ref array */ + Uint32 *new_array; + ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; + new_array = driver_realloc(ctxt->outstanding_refs, + ctxt->outstanding_refs_max*sizeof(Uint32)); + + if (!new_array) { + ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; + return 1; + } + + ctxt->outstanding_refs = new_array; + + memset(ctxt->outstanding_refs+ctxt->outstanding_refs_cnt,0, + REF_SEGMENT_SIZE*sizeof(Uint32)); + ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; + + } else { + /* Find an empty slot: + * First we try current index, + * then we scan for a slot. + */ + if (!ctxt->outstanding_refs[ctxt->outstanding_refs_cnt]) { + ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; + } else { + int i; + ASSERT(ctxt->outstanding_refs_cnt < ctxt->outstanding_refs_max); + for (i = 0; i < ctxt->outstanding_refs_max; i++) + if (!ctxt->outstanding_refs[i]) + break; + ASSERT(ctxt->outstanding_refs[i] == 0); + ctxt->outstanding_refs[i] = ref; + ctxt->outstanding_refs_cnt++; + } + } + return 0; +} + +/* Return 0 if removed, 1 if does not exist, */ +static int remove_reference(driver_context_t *ctxt, Uint32 ref) { + int i,j; + + if (ctxt->outstanding_refs_max == 0 && ctxt->outstanding_refs_cnt == 0) { + ASSERT(ctxt->outstanding_refs == NULL); + return 1; + } + + for (i = 0; i < ctxt->outstanding_refs_max; i++) { + if (ctxt->outstanding_refs[i] == ref) { + ctxt->outstanding_refs[i] = 0; + ctxt->outstanding_refs_cnt--; + i = -1; + break; + } + } + + if (i != -1) + return 1; + + if (ctxt->outstanding_refs_cnt == 0) { + driver_free(ctxt->outstanding_refs); + ctxt->outstanding_refs = NULL; + ctxt->outstanding_refs_max = 0; + } else if (ctxt->outstanding_refs_cnt == (ctxt->outstanding_refs_max - REF_SEGMENT_SIZE)) { + Uint32 *new_array; + for (i = 0, j = 0; i < ctxt->outstanding_refs_cnt; i++) { + if (ctxt->outstanding_refs[i] == 0) { + for (j = i+1; j < ctxt->outstanding_refs_max; j++) + if (ctxt->outstanding_refs[j]) { + ctxt->outstanding_refs[i] = ctxt->outstanding_refs[j]; + ctxt->outstanding_refs[j] = 0; + break; + } + } + } + ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; + new_array = driver_realloc(ctxt->outstanding_refs, + ctxt->outstanding_refs_max*sizeof(Uint32)); + if (!new_array) { + ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; + return 2; + } + + ctxt->outstanding_refs = new_array; + + } + + return 0; +} + +/** + * The OSE proxy process. This only handles ERTS_SIGNAL_OSE_DRV_ATTACH. + * The process is needed because signals triggered by attach ignore + * redir tables. + * + * We have one global proxy process to save memory. An attempt to make each + * port phantom into a proxy was made, but that used way to much memory. + */ +static OS_PROCESS(driver_proxy_process) { + SIGSELECT sigs[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH}; + PROCESS master = 0; + + while (1) { + union SIGNAL *sig = receive(sigs); + + if (sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { + + /* The first message is used to determine who to send messages to. */ + if (master == 0) + master = sender(&sig); + + if (sig->async.target == 0) { + PROCESS from = sender(&sig); + restore(sig); + DEBUGP_ATTACH("0x%x: got attach 0x%x, sending to 0x%x\n", + current_process(),from,master); + sig->async.target = from; + send(&sig,master); + } else { + PROCESS target = sig->async.target; + restore(sig); + sig->async.target = 0; + DEBUGP_ATTACH("0x%x: doing attach on 0x%x\n",current_process(),target); + attach(&sig,target); + } + } + } +} + +/** + * Init routine for the driver + **/ +static int drv_init(void) { + + a_ok = driver_mk_atom("ok"); + a_error = driver_mk_atom("error"); + a_enomem = driver_mk_atom("enomem"); + a_enoent = driver_mk_atom("enoent"); + a_badarg = driver_mk_atom("badarg"); + a_mailbox_up = driver_mk_atom("mailbox_up"); + a_mailbox_down = driver_mk_atom("mailbox_down"); + a_ose_drv_reply = driver_mk_atom("ose_drv_reply"); + a_message = driver_mk_atom("message"); + + proxy_proc = create_process(get_ptype(current_process()), + "ose_signal_driver_proxy", + driver_proxy_process, 10000, + get_pri(current_process()), + 0, 0, NULL, 0, 0); + +#ifdef DEBUG + efs_clone(proxy_proc); +#endif + start(proxy_proc); + + return 0; +} + +/** + * Start routine for the driver + **/ +static ErlDrvData drv_start(ErlDrvPort port, char *command) +{ + driver_context_t *ctxt = driver_alloc(sizeof(driver_context_t)); + + ctxt->perm_events[0] = NULL; + ctxt->perm_events[1] = NULL; + + ctxt->spid = 0; + ctxt->port = port; + ctxt->event_cnt = 0; + ctxt->events = NULL; + ctxt->ref = 0; + ctxt->outstanding_refs = NULL; + ctxt->outstanding_refs_max = 0; + ctxt->outstanding_refs_cnt = 0; + + + /* Set the communication protocol to Erlang to be binary */ + set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); + + /* Everything ok */ + return (ErlDrvData)ctxt; +} + +/** + * Stop routine for the driver + **/ +static void drv_stop(ErlDrvData driver_data) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + int i; + + /* HUNT + ATTACH */ + if (ctxt->perm_events[0]) + driver_select(ctxt->port, ctxt->perm_events[0], + ERL_DRV_USE|ERL_DRV_READ, 0); + if (ctxt->perm_events[1]) + driver_select(ctxt->port, ctxt->perm_events[1], + ERL_DRV_USE|ERL_DRV_READ, 0); + + for (i = 0; i < ctxt->event_cnt; i++) { + driver_select(ctxt->port, ctxt->events[i], ERL_DRV_USE|ERL_DRV_READ, 0); + } + + if (ctxt->spid != 0) + kill_proc(ctxt->spid); + DEBUGP("0x%x: stopped\n",ctxt->spid); + if (ctxt->events) + driver_free(ctxt->events); + if (ctxt->outstanding_refs) + driver_free(ctxt->outstanding_refs); + + driver_free(ctxt); +} + +/** + * Output from Erlang + **/ +static void outputv(ErlDrvData driver_data, ErlIOVec *ev) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + int p = 0, q = 1; + char cmd; + + if (! EV_GET_CHAR(ev,&cmd,&p,&q)) { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_badarg, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + return; + } + + /* Command is in the buffer's first byte */ + switch(cmd) { + + case OPEN: { + char *name = driver_alloc(ev->size - 1+1); + struct OS_redir_entry redir[2]; + + redir[0].sig = 1; + redir[0].pid = current_process(); + + iov_memcpy(name,ev,q,p); + name[ev->size-1] = '\0'; + + ctxt->spid = create_process(OS_PHANTOM, name, NULL, 0, + 0, 0, 0, redir, 0, 0); + + DEBUGP("0x%x: open\n",ctxt->spid); + + ctxt->perm_events[1] = + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid); + driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); + + ctxt->perm_events[0] = + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid); + driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); + + start(ctxt->spid); + + { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_ok, + ERL_DRV_TUPLE, 3}; + + send_response(ctxt->port, output); + } + + break; + + } + + case ATTACH: + case HUNT: + { + union SIGNAL *sig = alloc(sizeof(union SIGNAL), + cmd == HUNT ? ERTS_SIGNAL_OSE_DRV_HUNT:ERTS_SIGNAL_OSE_DRV_ATTACH); + + sig->async.port = driver_mk_port(ctxt->port); + sig->async.proc = driver_caller(ctxt->port); + sig->async.spid = ctxt->spid; + sig->async.ref = ++ctxt->ref; + + if (add_reference(ctxt,ctxt->ref)) { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_enomem, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + free_buf(&sig); + } else { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_INT, (ErlDrvUInt)ctxt->ref, + ERL_DRV_TUPLE, 2, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + + if (cmd == HUNT) { + char *huntname = driver_alloc(sizeof(char)*((ev->size-1)+1)); + + iov_memcpy(huntname,ev,q,p); + huntname[ev->size-1] = '\0'; + + DEBUGP_HUNT("0x%x: hunt %s -> %u (%u,%u)\n", + ctxt->spid,huntname,ctxt->ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + + hunt(huntname, 0, NULL, &sig); + + driver_free(huntname); + } else { + EV_GET_UINT32(ev,&sig->async.target,&p,&q); + DEBUGP_ATTACH("0x%x: attach %u -> %u (%u,%u)\n", + ctxt->spid,sig->async.target, + ctxt->ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + + send(&sig,proxy_proc); + } + + } + + break; + } + + case DETACH: + case DEHUNT: + { + + Uint32 ref; + + EV_GET_UINT32(ev,&ref,&p,&q); + if (cmd == DETACH) { + DEBUGP_ATTACH("0x%x: detach %u (%u,%u)\n",ctxt->spid,ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + } else { + DEBUGP_HUNT("0x%x: dehunt %u (%u,%u)\n",ctxt->spid,ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + } + + if (remove_reference(ctxt,ref)) { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_error, + ERL_DRV_ATOM, a_enoent, + ERL_DRV_TUPLE, 2, + ERL_DRV_TUPLE, 3}; + + send_response(ctxt->port, output); + } else { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_ok, + ERL_DRV_TUPLE, 3}; + + send_response(ctxt->port, output); + } + + break; + } + + case SEND: + case SEND_W_S: + { + PROCESS spid; + PROCESS sender; + SIGSELECT signo; + OSBUFSIZE size = ev->size-9; + union SIGNAL *sig; + + EV_GET_UINT32(ev,&spid,&p,&q); + + if (cmd == SEND_W_S) { + EV_GET_UINT32(ev,&sender,&p,&q); + size -= 4; + } else { + sender = ctxt->spid; + } + + EV_GET_UINT32(ev,&signo,&p,&q); + + sig = alloc(size + sizeof(SIGSELECT),signo); + + if (cmd == SEND_W_S) { + DEBUGP_SEND("0x%x: send_w_s(%u,%u,%u)\n",ctxt->spid,spid,signo,sender); + } else { + DEBUGP_SEND("0x%x: send(%u,%u)\n",ctxt->spid,spid,signo); + } + + iov_memcpy(((char *)&sig->signo) + sizeof(SIGSELECT),ev,q,p); + + send_w_s(&sig, sender, spid); + + break; + } + + case LISTEN: + { + int i,j,event_cnt = (ev->size - 1)/4; + ErlDrvEvent *events = NULL; + SIGSELECT signo,tmp_signo; + + if (event_cnt == 0) { + for (i = 0; i < ctxt->event_cnt; i++) + driver_select(ctxt->port,ctxt->events[i],ERL_DRV_READ|ERL_DRV_USE,0); + if (ctxt->events) + driver_free(ctxt->events); + } else { + events = driver_alloc(sizeof(ErlDrvEvent)*event_cnt); + EV_GET_UINT32(ev,&signo,&p,&q); + for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) { + + if (ctxt->events) + erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL); + + if (signo == tmp_signo) { + events[i++] = ctxt->events[j++]; + EV_GET_UINT32(ev,&signo,&p,&q); + } else if (signo < tmp_signo || !ctxt->events) { + /* New signal to select on */ + events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid); + driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); + EV_GET_UINT32(ev,&signo,&p,&q); + } else { + /* Remove old signal to select on */ + driver_select(ctxt->port,ctxt->events[j++],ERL_DRV_READ|ERL_DRV_USE,0); + } + } + if (ctxt->events) + driver_free(ctxt->events); + } + ctxt->events = events; + ctxt->event_cnt = event_cnt; + + { + ErlDrvTermData output[] = { + ERL_DRV_ATOM, a_ose_drv_reply, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_ATOM, a_ok, + ERL_DRV_TUPLE, 3}; + send_response(ctxt->port, output); + } + break; + } + + default: + { + DEBUGP("Warning: 'ose_signal_drv' unknown command '%d'\n", cmd); + break; + } + } +} + +/** + * Handler for when OSE signal arrives + **/ +static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + union SIGNAL *sig = erl_drv_ose_get_input_signal(event); + + while (sig != NULL) { + + switch(sig->signo) + { + /* Remote process is available */ + case ERTS_SIGNAL_OSE_DRV_HUNT: + { + const PROCESS spid = sender(&sig); + + if (remove_reference(ctxt,sig->async.ref)) { + DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (CANCELLED) (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + /* Already removed by dehunt */ + } else { + ErlDrvTermData reply[] = { + ERL_DRV_ATOM, a_mailbox_up, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_UINT, (ErlDrvUInt)sig->async.ref, + ERL_DRV_TUPLE, 2, + ERL_DRV_UINT, (ErlDrvUInt)spid, + ERL_DRV_TUPLE, 4}; + DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + erl_drv_send_term(sig->async.port, sig->async.proc, reply, + sizeof(reply) / sizeof(reply[0])); + } + break; + } + + /* Remote process is down */ + case ERTS_SIGNAL_OSE_DRV_ATTACH: + { + PROCESS spid = sig->async.target; + + if (remove_reference(ctxt,sig->async.ref)) { + DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (CANCELLED) (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + /* Already removed by detach */ + } else { + ErlDrvTermData reply[] = { + ERL_DRV_ATOM, a_mailbox_down, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_PORT, sig->async.port, + ERL_DRV_UINT, sig->async.ref, + ERL_DRV_TUPLE, 2, + ERL_DRV_UINT, (ErlDrvUInt)spid, + ERL_DRV_TUPLE, 4}; + DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (%u,%u)\n", + ctxt->spid,spid,sig->async.ref, + ctxt->outstanding_refs_cnt, + ctxt->outstanding_refs_max); + erl_drv_send_term(sig->async.port, sig->async.proc, reply, + sizeof(reply) / sizeof(reply[0])); + } + break; + } + + /* Received user defined signal */ + default: + { + const PROCESS spid = sender(&sig); + const OSBUFSIZE size = sigsize(&sig) - sizeof(SIGSELECT); + const char *sig_data = ((char *)&sig->signo) + sizeof(SIGSELECT); + + ErlDrvTermData reply[] = { + ERL_DRV_ATOM, a_message, + ERL_DRV_PORT, driver_mk_port(ctxt->port), + ERL_DRV_UINT, (ErlDrvUInt)spid, + ERL_DRV_UINT, (ErlDrvUInt)ctxt->spid, + ERL_DRV_UINT, (ErlDrvUInt)sig->signo, + ERL_DRV_BUF2BINARY, (ErlDrvTermData)sig_data, (ErlDrvUInt)size, + ERL_DRV_TUPLE, 4, + ERL_DRV_TUPLE, 3}; + + DEBUGP_SEND("0x%x: Got 0x%u\r\n", spid, sig->signo); + + erl_drv_output_term(driver_mk_port(ctxt->port), reply, + sizeof(reply) / sizeof(reply[0])); + break; + } + } + + free_buf(&sig); + sig = erl_drv_ose_get_input_signal(event); + } +} + +/** + * Handler for 'port_control' + **/ +static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) +{ + driver_context_t *ctxt = (driver_context_t *)driver_data; + + switch(cmd) + { + case GET_SPID: + { + const PROCESS spid = ctxt->spid; + put_u32(spid, *rbuf); + return sizeof(PROCESS); + } + + case GET_NAME: + { + const PROCESS spid = get_u32(buf); + char *name = (char*)get_pid_info(spid,OSE_PI_NAME); + int n; + if (!name) { + *rbuf = NULL; + return 0; + } + + if (rlen < (n = strlen(name))) { + ErlDrvBinary *bin = driver_alloc_binary(n); + strncpy(bin->orig_bytes,name,n); + *rbuf = (char*)bin; + } else + strncpy(*rbuf,name,n); + free_buf((union SIGNAL**)&name); + + return n; + } + default: + { + /* Unknown command */ + return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL; + break; + } + } +} + +static void stop_select(ErlDrvEvent event, void *reserved) +{ + erl_drv_ose_event_free(event); +} + +static int resolve_signal(OseSignal* osig, int *mode) { + union SIGNAL *sig = osig; + if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || + sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { + return sig->async.spid; + } + DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", + current_process(),sig->signo,addressee(&sig),sender(&sig)); + return addressee(&sig); +} + +/** + * Setup the driver entry for the Erlang runtime + **/ +ErlDrvEntry ose_signal_driver_entry = { + .init = drv_init, + .start = drv_start, + .stop = drv_stop, + .outputv = outputv, + .ready_input = ready_input, + .driver_name = DRIVER_NAME, + .control = control, + .extended_marker = ERL_DRV_EXTENDED_MARKER, + .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, + .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, + .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING, + .stop_select = stop_select, + .resolve_signal = resolve_signal +}; -- cgit v1.2.3 From a6788ea337a2319a2d1a42ee4618553a1c7765bf Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Wed, 30 Oct 2013 17:56:37 +0100 Subject: ose: Fix various build environment issues --- erts/emulator/drivers/ose/ose_signal_drv.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index acf09f748e..c1d861cc5a 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -28,7 +28,10 @@ #include "sys.h" #include "erl_driver.h" #include "ose.h" + +#ifdef HAVE_OSE_SPI_H #include "ose_spi/ose_spi.h" +#endif #define DEBUG_ATTACH 0 #define DEBUG_HUNT 0 @@ -819,6 +822,7 @@ static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, return sizeof(PROCESS); } +#ifdef HAVE_OSE_SPI_H case GET_NAME: { const PROCESS spid = get_u32(buf); @@ -839,6 +843,7 @@ static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, return n; } +#endif default: { /* Unknown command */ -- cgit v1.2.3 From cbfff8e7148a51a76f31effc6b2486f4bda927f6 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 1 Nov 2013 18:00:11 +0100 Subject: ose: Handle lseek() with offset beyond EOF in the file driver. --- erts/emulator/drivers/ose/ose_efile.c | 316 +++++++++++++++++++++++++++++++--- 1 file changed, 288 insertions(+), 28 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index fc255e11ef..897d654e89 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -62,11 +62,13 @@ #endif #ifdef __OSE__ +#include "ose.h" #include "unistd.h" #include "sys/stat.h" #include "dirent.h" #include "sys/time.h" #include "time.h" +#include "heapapi.h" #endif /* Find a definition of MAXIOV, that is used in the code later. */ @@ -99,8 +101,142 @@ #define IS_DOT_OR_DOTDOT(s) \ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) + +/* + * Local file descriptor handling, this is needed for filesystems + * that does not handle seeking outside EOF. + */ + +#define L_FD_EXISTS(fd) \ + ((fdm->is_init == 1) && fdm->fd_array[(fd)] != NULL) + +#define L_FD_INVALIDATE(fd) \ + fdm->fd_array[(fd)]->valid = 0 + +#define L_FD_IS_VALID(fd) \ + (fdm->fd_array[(fd)]->valid == 1) + +#define L_FD_OFFSET_BEYOND_EOF(fd, offset) \ + (fdm->fd_array[(fd)]->size < offset) + +#define L_FD_CUR(fd) \ + (fdm->fd_array[(fd)]->pos) + + +struct fd_meta +{ + int is_init; + uint32_t fd_count; + struct fd_data *fd_array[256]; +}; + +struct fd_data +{ + int pos; + int whence; + int valid; + size_t size; +}; + +static struct fd_meta *fdm; +static int l_init_local_fd(void); +static int l_pad_file(int fd, off_t offset); +static int l_update_local_fd(int fd, off_t offset, int whence); + static int check_error(int result, Efile_error* errInfo); +static int +l_init_local_fd() +{ + fdm = heap_alloc_private(sizeof(struct fd_meta), __FILE__, __LINE__); + fdm->fd_count = 0; + fdm->is_init = 1; + + memset(fdm->fd_array, NULL, sizeof(fdm->fd_array)); + return 1; +} + +static int +l_update_local_fd(int fd, off_t offset, int whence) +{ + errno = 0; + + if (fdm->fd_array[fd] == NULL) + { + fdm->fd_array[fd] = heap_alloc_private(sizeof(struct fd_data), __FILE__, __LINE__); + fdm->fd_count++; + } + + switch (whence) + { + case SEEK_CUR: + fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_CUR) + offset; + break; + + case SEEK_END: + fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_END) + offset; + break; + + case SEEK_SET: + fdm->fd_array[fd]->pos = offset; + + default: + errno = ENOSYS; + break; + } + fdm->fd_array[fd]->size = lseek(fd, 0, SEEK_END); + + fdm->fd_array[fd]->whence = whence; + fdm->fd_array[fd]->valid = 1; + + return ((errno != 0) ? -1 : 1); +} + +static int +l_pad_file(int fd, off_t offset) +{ + int size_dif; + char *pad; + char *cursor; + int file_size; + int written = 0; + + if (!L_FD_IS_VALID(fd)) + { + l_update_local_fd(fd, offset, SEEK_END); + } + + if (!L_FD_OFFSET_BEYOND_EOF(fd, offset)) + { + + return -1; + } + + + file_size = lseek(fd, 0, SEEK_END); + size_dif = offset - file_size; + pad = heap_alloc_private(size_dif, __FILE__, __LINE__); + cursor = pad; + memset(pad, '\0', size_dif); + + while (size_dif > 0) + { + written = write(fd, cursor, size_dif); + + if (written < 0) + { + return -1; + } + cursor += written; + size_dif -= written; + } + + L_FD_INVALIDATE(fd); + heap_free_private(pad); + + return ((errno != 0) ? -1 : 1); +} + static int check_error(int result, Efile_error *errInfo) { @@ -111,6 +247,10 @@ check_error(int result, Efile_error *errInfo) return 1; } +/* + * public API + */ + int efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */ @@ -155,6 +295,15 @@ int efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of file to delete. */ { + struct stat statbuf; + + /* OSE will accept removal of directories with unlink() */ + if (stat(name, &statbuf) >= 0 && ISDIR(statbuf)) + { + errno = EPERM; + return check_error(-1, errInfo); + } + if (unlink(name) == 0) { return 1; } @@ -202,7 +351,22 @@ efile_rename(Efile_error* errInfo, /* Where to return error codes. */ char* src, /* Original name. */ char* dst) /* New name. */ { - if (rename(src, dst) == 0) { + + /* temporary fix AFM does not recognize ./ + * in destination */ + + char *dot_str; + if (dst != NULL) + { + dot_str = strchr(dst, '.'); + + if (dot_str && dot_str == dst && dot_str[1] == '/') + { + dst = dst+2; + } + } + + if (rename(src, dst) == 0) { return 1; } if (errno == ENOTEMPTY) { @@ -445,7 +609,12 @@ efile_may_openfile(Efile_error* errInfo, char *name) { void efile_closefile(int fd) { - close(fd); + if (L_FD_EXISTS(fd)) + { + free(fdm->fd_array[fd]); + fdm->fd_array[fd] = NULL; + } + close(fd); } int @@ -546,6 +715,10 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, int efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { +/* FIXME, this will be dificult to get to work right with the tests on ose + * reason being that the info values are sometimes used in different ways, and in + * some times not used at all. */ + #ifndef __OSE__ struct utimbuf tval; #endif @@ -593,16 +766,40 @@ efile_write(Efile_error* errInfo, /* Where to return error codes. */ { ssize_t written; /* Bytes written in last operation. */ - while (count > 0) { - if ((written = write(fd, buf, count)) < 0) { - if (errno != EINTR) - return check_error(-1, errInfo); - else - written = 0; - } - ASSERT(written <= count); - buf += written; - count -= written; + if (L_FD_EXISTS(fd)) + { + off_t off; + off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); + + if (L_FD_OFFSET_BEYOND_EOF(fd, off)) + { + l_pad_file(fd, off); + } + + L_FD_INVALIDATE(fd); + } + + while (count > 0) + { + if ((written = write(fd, buf, count)) < 0) + { + if (errno != EINTR) + { + return check_error(-1, errInfo); + } + else + { + written = 0; + } + } + ASSERT(written <= count); + buf += written; + count -= written; + } + + if (L_FD_EXISTS(fd)) + { + L_FD_INVALIDATE(fd); } return 1; } @@ -676,12 +873,38 @@ efile_read(Efile_error* errInfo, /* Where to return error codes. */ bytes read. */ { ssize_t n; + if (L_FD_EXISTS(fd)) + { + off_t off; + off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); + if (L_FD_IS_VALID(fd) == 0) + { + l_update_local_fd(fd, off, SEEK_SET); + } - for (;;) { - if ((n = read(fd, buf, count)) >= 0) - break; - else if (errno != EINTR) - return check_error(-1, errInfo); + if (L_FD_OFFSET_BEYOND_EOF(fd, off)) + { + *pBytesRead = 0; + return 1; + } + /* FIXME .. is this needed? */ + lseek(fd, off, SEEK_SET); + } + + for (;;) + { + if ((n = read(fd, buf, count)) >= 0) + { + break; + } + else if (errno != EINTR) + { + return check_error(-1, errInfo); + } + } + if (n != 0 && L_FD_EXISTS(fd)) + { + L_FD_INVALIDATE(fd); } *pBytesRead = (size_t) n; return 1; @@ -789,6 +1012,7 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ Sint64 *new_location) /* Resulting new location in file. */ { off_t off, result; + off = (off_t) offset; switch (origin) { case EFILE_SEEK_SET: origin = SEEK_SET; break; @@ -798,15 +1022,19 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ errno = EINVAL; return check_error(-1, errInfo); } - off = (off_t) offset; if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); + errno = EINVAL; + return check_error(-1, errInfo); } errno = 0; result = lseek(fd, off, origin); + if (result >= 0 && L_FD_EXISTS(fd)) + { + L_FD_INVALIDATE(fd); + } + /* * Note that the man page for lseek (on SunOs 5) says: * @@ -815,14 +1043,40 @@ efile_seek(Efile_error* errInfo, /* Where to return error codes. */ * negative." */ - if (result < 0 && errno == 0) - errno = EINVAL; - if (result < 0) - return check_error(-1, errInfo); - if (new_location) { - *new_location = result; - } - return 1; + if (result < 0 && errno == 0) + errno = EINVAL; + if (result < 0) + { + /* Some filesystems on OSE does not handle seeking beyond EOF + * We handle this here, by localy storing offsets. */ + + if ((lseek(fd, 0, SEEK_END) < off) && errno == 78) + { + if (fdm == NULL) /* first time */ + { + if (l_init_local_fd() == -1) + { + errno = EINVAL; + check_error(-1, errInfo); + } + } + l_update_local_fd(fd, off, origin); + result = off; + } + else if (off < 0 && errno == ENOSYS) + { + errno = EINVAL; + return check_error(-1, errInfo); + } + else + { + return check_error(-1, errInfo); + } + } + if (new_location) { + *new_location = result; + } + return 1; } @@ -831,6 +1085,12 @@ efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { #ifndef NO_FTRUNCATE off_t offset; + + if (L_FD_EXISTS(fileno(fd))) + { + L_FD_INVALIDATE(fileno(fd)); + } + return check_error((offset = lseek(*fd, 0, SEEK_CUR)) >= 0 && ftruncate(*fd, offset) == 0 ? 1 : -1, errInfo); #else -- cgit v1.2.3 From a0766a4efeefe0ac035d2be04816274aee5751f3 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 8 Nov 2013 14:00:36 +0100 Subject: ose: Bugfixes to filesystem related issues. --- erts/emulator/drivers/ose/ose_efile.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 897d654e89..9980b07817 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -258,7 +258,11 @@ efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ #ifdef NO_MKDIR_MODE return check_error(mkdir(name), errInfo); #else - return check_error(mkdir(name, DIR_MODE), errInfo); + int res = mkdir(name, DIR_MODE); + if (res < 0 && errno == EINVAL) { + errno = ENOENT; + } + return check_error(res, errInfo); #endif } -- cgit v1.2.3 From 3d24208d607501207af371098c1466758844e667 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 22 Nov 2013 09:45:05 +0100 Subject: ose: efile driver updates. --- erts/emulator/drivers/common/efile_drv.c | 8 +- erts/emulator/drivers/common/erl_efile.h | 2 +- erts/emulator/drivers/ose/ose_efile.c | 1531 +++++++++++++----------------- erts/emulator/drivers/unix/unix_efile.c | 5 + erts/emulator/drivers/win32/win_efile.c | 5 + 5 files changed, 665 insertions(+), 886 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index fbd72c6c1b..7ef985dc41 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -373,9 +373,6 @@ struct erl_drv_entry efile_driver_entry = { #else NULL #endif /* HAVE_SENDFILE */ -#ifdef __OSE__ - ,NULL -#endif }; @@ -768,6 +765,9 @@ file_init(void) : 0); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); + /* run initiation of efile_driver if needed */ + efile_init(); + #ifdef USE_VM_PROBES erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex"); pthread_key_create(&dt_driver_key, NULL); @@ -914,6 +914,7 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num, driver_output2(desc->port, response, t-response, NULL, 0); } +#ifdef HAVE_SENDFILE static void reply_string_error(file_descriptor *desc, char* str) { char response[256]; /* Response buffer. */ char* s; @@ -924,6 +925,7 @@ static void reply_string_error(file_descriptor *desc, char* str) { *t = tolower(*s); driver_output2(desc->port, response, t-response, NULL, 0); } +#endif static int reply_error(file_descriptor *desc, Efile_error *errInfo) /* The error codes. */ diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 95c036db8f..5a8e3bc5db 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -127,7 +127,7 @@ struct t_sendfile_hdtl { /* * Functions. */ - +int efile_init(void); int efile_mkdir(Efile_error* errInfo, char* name); int efile_rmdir(Efile_error* errInfo, char* name); int efile_delete_file(Efile_error* errInfo, char* name); diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c index 9980b07817..035ff81a9b 100644 --- a/erts/emulator/drivers/ose/ose_efile.c +++ b/erts/emulator/drivers/ose/ose_efile.c @@ -31,45 +31,16 @@ #include "sys.h" #include "erl_driver.h" #include "erl_efile.h" -/*#include */ -#ifdef HAVE_UNISTD_H -#ifndef __OSE__ -#include -#endif -#endif -#ifdef HAVE_SYS_UIO_H -#include -#include -#endif -#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) -#include -#endif - -#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define DARWIN 1 -#endif - #if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) -#include -#endif - -#ifdef HAVE_LINUX_FALLOC_H -#include +#include "fcntl.h" #endif - -#ifdef SUNOS4 -# define getcwd(buf, size) getwd(buf) -#endif - -#ifdef __OSE__ #include "ose.h" #include "unistd.h" #include "sys/stat.h" #include "dirent.h" #include "sys/time.h" #include "time.h" -#include "heapapi.h" -#endif +#include "assert.h" /* Find a definition of MAXIOV, that is used in the code later. */ #if defined IOV_MAX @@ -80,7 +51,6 @@ #define MAXIOV 16 #endif - /* * Macros for testing file types. */ @@ -88,7 +58,7 @@ #define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR) #define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG) #define ISDEV(st) \ - (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) + (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) #define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK) #ifdef NO_UMASK #define FILE_MODE 0644 @@ -101,159 +71,261 @@ #define IS_DOT_OR_DOTDOT(s) \ (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) - /* - * Local file descriptor handling, this is needed for filesystems - * that does not handle seeking outside EOF. + * Macros for handling local file descriptors + * and mutexes. + * + * Handling of files like this is necessary because OSE + * does not allow seeking after the end of a file. So + * what we do it emulate this by keeping track of the size + * of the file and where the file's positions is. If a + * write happens after eof then we pad it. + * + * Given time this should be rewritten to get rid of the + * mutex and use the port lock to protect the data. This + * could be done be done by adapting the efile api for some + * calls to allow some meta-data to be associated with the + * open file. */ -#define L_FD_EXISTS(fd) \ - ((fdm->is_init == 1) && fdm->fd_array[(fd)] != NULL) +#define L_FD_IS_VALID(fd_data) ((fd_data)->beyond_eof > 0) +#define L_FD_INVALIDATE(fd_data) (fd_data)->beyond_eof = 0 +#define L_FD_CUR(fd_data) (fd_data)->pos +#define L_FD_OFFS_BEYOND_EOF(fd_data, offs) \ + (((fd_data)->size > offs) ? 0 : 1) + +#define L_FD_FAIL -1 +#define L_FD_SUCCESS 1 +#define L_FD_PAD_SIZE 255 -#define L_FD_INVALIDATE(fd) \ - fdm->fd_array[(fd)]->valid = 0 +struct fd_meta { + ErlDrvMutex *meta_mtx; + struct fd_data *fd_data_list; +}; -#define L_FD_IS_VALID(fd) \ - (fdm->fd_array[(fd)]->valid == 1) +struct fd_data { + int fd; + struct fd_data *next; + struct fd_data *prev; + int pos; + int beyond_eof; + size_t size; +#ifdef DEBUG + PROCESS owner; +#endif +}; -#define L_FD_OFFSET_BEYOND_EOF(fd, offset) \ - (fdm->fd_array[(fd)]->size < offset) +static int l_invalidate_local_fd(int fd); +static int l_pad_file(struct fd_data *fd_data, off_t offset); +static int check_error(int result, Efile_error* errInfo); +static struct fd_data* l_new_fd(void); +static int l_remove_local_fd(int fd); +static struct fd_data* l_find_local_fd(int fd); +static int l_update_local_fd(int fd, int pos, int size); -#define L_FD_CUR(fd) \ - (fdm->fd_array[(fd)]->pos) +static struct fd_meta* fdm = NULL; -struct fd_meta -{ - int is_init; - uint32_t fd_count; - struct fd_data *fd_array[256]; -}; +/***************************************************************************/ -struct fd_data +static int +l_remove_local_fd(int fd) { - int pos; - int whence; - int valid; - size_t size; -}; + struct fd_data *fd_data; + fd_data = l_find_local_fd(fd); + + if (fd_data == NULL) { + return L_FD_FAIL; + } +#ifdef DEBUG + assert(fd_data->owner == current_process()); +#endif + erl_drv_mutex_lock(fdm->meta_mtx); + /* head ? */ + if (fd_data == fdm->fd_data_list) { + if (fd_data->next != NULL) { + /* remove link to head */ + fd_data->next->prev = NULL; + /* set new head */ + fdm->fd_data_list = fd_data->next; + } + else { + /* head is lonely */ + fdm->fd_data_list = NULL; + } + } + else { /* not head */ + if (fd_data->prev == NULL) { + erl_drv_mutex_unlock(fdm->meta_mtx); + return L_FD_FAIL; + } + else { + if (fd_data->next != NULL) { + fd_data->next->prev = fd_data->prev; + fd_data->prev->next = fd_data->next; + } + else { + fd_data->prev->next = NULL; + } + } + } -static struct fd_meta *fdm; -static int l_init_local_fd(void); -static int l_pad_file(int fd, off_t offset); -static int l_update_local_fd(int fd, off_t offset, int whence); + /* scramble values */ + fd_data->beyond_eof = -1; + fd_data->next = NULL; + fd_data->prev = NULL; + fd_data->fd = -1; -static int check_error(int result, Efile_error* errInfo); + /* unlock and clean */ + driver_free(fd_data); + erl_drv_mutex_unlock(fdm->meta_mtx); + + return L_FD_SUCCESS; +} + +/***************************************************************************/ static int -l_init_local_fd() -{ - fdm = heap_alloc_private(sizeof(struct fd_meta), __FILE__, __LINE__); - fdm->fd_count = 0; - fdm->is_init = 1; +l_invalidate_local_fd(int fd) { + struct fd_data *fd_data; + + if ((fd_data = l_find_local_fd(fd)) == NULL) { + return L_FD_FAIL; + } - memset(fdm->fd_array, NULL, sizeof(fdm->fd_array)); - return 1; + fd_data->beyond_eof = 0; + return L_FD_SUCCESS; } -static int -l_update_local_fd(int fd, off_t offset, int whence) -{ - errno = 0; +/****************************************************************************/ - if (fdm->fd_array[fd] == NULL) - { - fdm->fd_array[fd] = heap_alloc_private(sizeof(struct fd_data), __FILE__, __LINE__); - fdm->fd_count++; - } +static struct fd_data* +l_find_local_fd(int fd) { + struct fd_data *fd_data; - switch (whence) - { - case SEEK_CUR: - fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_CUR) + offset; - break; + fd_data = NULL; + erl_drv_mutex_lock(fdm->meta_mtx); + for (fd_data = fdm->fd_data_list; fd_data != NULL; ) { + if (fd_data->fd == fd) { +#ifdef DEBUG + assert(fd_data->owner == current_process()); +#endif + break; + } + fd_data = fd_data->next; + } + erl_drv_mutex_unlock(fdm->meta_mtx); + return fd_data; +} + +/***************************************************************************/ - case SEEK_END: - fdm->fd_array[fd]->pos = lseek(fd, 0, SEEK_END) + offset; - break; +static struct fd_data* +l_new_fd(void) { + struct fd_data *fd_data; - case SEEK_SET: - fdm->fd_array[fd]->pos = offset; + fd_data = driver_alloc(sizeof(struct fd_data)); + if (fd_data == NULL) { + return NULL; + } + erl_drv_mutex_lock(fdm->meta_mtx); + if (fdm->fd_data_list == NULL) { + fdm->fd_data_list = fd_data; + fdm->fd_data_list->prev = NULL; + fdm->fd_data_list->next = NULL; + } + else { + fd_data->next = fdm->fd_data_list; + fdm->fd_data_list = fd_data; + fdm->fd_data_list->prev = NULL; + } +#ifdef DEBUG + fd_data->owner = current_process(); +#endif + erl_drv_mutex_unlock(fdm->meta_mtx); + return fd_data; +} - default: - errno = ENOSYS; - break; - } - fdm->fd_array[fd]->size = lseek(fd, 0, SEEK_END); +/***************************************************************************/ - fdm->fd_array[fd]->whence = whence; - fdm->fd_array[fd]->valid = 1; +static int +l_update_local_fd(int fd, int pos, int size) { + struct fd_data *fd_data = NULL; + + fd_data = l_find_local_fd(fd); + /* new fd to handle? */ + if (fd_data == NULL) { + fd_data = l_new_fd(); + if (fd_data == NULL) { + /* out of memory */ + return L_FD_FAIL; + } + } + fd_data->size = size; + fd_data->pos = pos; + fd_data->fd = fd; + fd_data->beyond_eof = 1; - return ((errno != 0) ? -1 : 1); + return L_FD_SUCCESS; } +/***************************************************************************/ + static int -l_pad_file(int fd, off_t offset) -{ - int size_dif; - char *pad; - char *cursor; - int file_size; - int written = 0; - - if (!L_FD_IS_VALID(fd)) - { - l_update_local_fd(fd, offset, SEEK_END); - } - - if (!L_FD_OFFSET_BEYOND_EOF(fd, offset)) - { - - return -1; - } - - - file_size = lseek(fd, 0, SEEK_END); - size_dif = offset - file_size; - pad = heap_alloc_private(size_dif, __FILE__, __LINE__); - cursor = pad; - memset(pad, '\0', size_dif); - - while (size_dif > 0) - { - written = write(fd, cursor, size_dif); - - if (written < 0) - { - return -1; - } - cursor += written; - size_dif -= written; - } - - L_FD_INVALIDATE(fd); - heap_free_private(pad); - - return ((errno != 0) ? -1 : 1); +l_pad_file(struct fd_data *fd_data, off_t offset) { + int size_dif; + int written = 0; + int ret_val = L_FD_SUCCESS; + char padding[L_FD_PAD_SIZE]; + + size_dif = (offset - fd_data->size); + memset(&padding, '\0', L_FD_PAD_SIZE); + + while (size_dif > 0) { + written = write(fd_data->fd, padding, + (size_dif < L_FD_PAD_SIZE) ? + size_dif : L_FD_PAD_SIZE); + if (written < 0 && errno != EINTR && errno != EAGAIN) { + ret_val = -1; + break; + } + size_dif -= written; + } + L_FD_INVALIDATE(fd_data); + return ret_val; } +/***************************************************************************/ + static int -check_error(int result, Efile_error *errInfo) -{ +check_error(int result, Efile_error *errInfo) { if (result < 0) { - errInfo->posix_errno = errInfo->os_errno = errno; - return 0; + errInfo->posix_errno = errInfo->os_errno = errno; + return 0; } return 1; } -/* - * public API - */ +/***************************************************************************/ + +int +efile_init() { + fdm = driver_alloc(sizeof(struct fd_meta)); + if (fdm == NULL) { + return L_FD_FAIL; + } + fdm->meta_mtx = erl_drv_mutex_create("ose_efile local fd mutex\n"); + erl_drv_mutex_lock(fdm->meta_mtx); + fdm->fd_data_list = NULL; + erl_drv_mutex_unlock(fdm->meta_mtx); + return L_FD_SUCCESS; +} + +/***************************************************************************/ int -efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to create. */ +efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to create. */ { #ifdef NO_MKDIR_MODE return check_error(mkdir(name), errInfo); @@ -266,53 +338,69 @@ efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ #endif } +/***************************************************************************/ + int -efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to delete. */ +efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of directory to delete. */ { if (rmdir(name) == 0) { - return 1; + return 1; } if (errno == ENOTEMPTY) { - errno = EEXIST; + errno = EEXIST; } - if (errno == EEXIST) { - int saved_errno = errno; - struct stat file_stat; - struct stat cwd_stat; - - /* - * The error code might be wrong if this is the current directory. - */ - - if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && - file_stat.st_ino == cwd_stat.st_ino && - file_stat.st_dev == cwd_stat.st_dev) { - saved_errno = EINVAL; - } - errno = saved_errno; + if (errno == EEXIST || errno == EINVAL) { + int saved_errno = errno; + struct stat file_stat; + struct stat cwd_stat; + + if(stat(name, &file_stat) != 0) { + errno = ENOENT; + return check_error(-1, errInfo); + } + /* + * The error code might be wrong if this is the current directory. + */ + if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && + file_stat.st_ino == cwd_stat.st_ino && + file_stat.st_dev == cwd_stat.st_dev) { + saved_errno = EACCES; + } + errno = saved_errno; } return check_error(-1, errInfo); } +/***************************************************************************/ + int -efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of file to delete. */ +efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ + char* name) /* Name of file to delete. */ { struct stat statbuf; - /* OSE will accept removal of directories with unlink() */ - if (stat(name, &statbuf) >= 0 && ISDIR(statbuf)) - { - errno = EPERM; - return check_error(-1, errInfo); - } + if (stat(name, &statbuf) >= 0) { + /* Do not let unlink() remove directories */ + if (ISDIR(statbuf)) { + errno = EPERM; + return check_error(-1, errInfo); + } - if (unlink(name) == 0) { - return 1; + if (unlink(name) == 0) { + return 1; + } + + if (errno == EISDIR) { + errno = EPERM; + return check_error(-1, errInfo); + } } - if (errno == EISDIR) { /* Linux sets the wrong error code. */ - errno = EPERM; + else { + if (errno == EINVAL) { + errno = ENOENT; + return check_error(-1, errInfo); + } } return check_error(-1, errInfo); } @@ -321,150 +409,107 @@ efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ *--------------------------------------------------------------------------- * * Changes the name of an existing file or directory, from src to dst. - * If src and dst refer to the same file or directory, does nothing - * and returns success. Otherwise if dst already exists, it will be - * deleted and replaced by src subject to the following conditions: - * If src is a directory, dst may be an empty directory. - * If src is a file, dst may be a file. - * In any other situation where dst already exists, the rename will - * fail. + * If src and dst refer to the same file or directory, does nothing + * and returns success. Otherwise if dst already exists, it will be + * deleted and replaced by src subject to the following conditions: + * If src is a directory, dst may be an empty directory. + * If src is a file, dst may be a file. + * In any other situation where dst already exists, the rename will + * fail. * * Results: - * If the directory was successfully created, returns 1. - * Otherwise the return value is 0 and errno is set to - * indicate the error. Some possible values for errno are: + * If the directory was successfully created, returns 1. + * Otherwise the return value is 0 and errno is set to + * indicate the error. Some possible values for errno are: * - * EACCES: src or dst parent directory can't be read and/or written. - * EEXIST: dst is a non-empty directory. - * EINVAL: src is a root directory or dst is a subdirectory of src. - * EISDIR: dst is a directory, but src is not. - * ENOENT: src doesn't exist, or src or dst is "". - * ENOTDIR: src is a directory, but dst is not. - * EXDEV: src and dst are on different filesystems. + * EACCES: src or dst parent directory can't be read and/or written. + * EEXIST: dst is a non-empty directory. + * EINVAL: src is a root directory or dst is a subdirectory of src. + * EISDIR: dst is a directory, but src is not. + * ENOENT: src doesn't exist, or src or dst is "". + * ENOTDIR: src is a directory, but dst is not. + * EXDEV: src and dst are on different filesystems. * * Side effects: - * The implementation of rename may allow cross-filesystem renames, - * but the caller should be prepared to emulate it with copy and - * delete if errno is EXDEV. + * The implementation of rename may allow cross-filesystem renames, + * but the caller should be prepared to emulate it with copy and + * delete if errno is EXDEV. * *--------------------------------------------------------------------------- */ int -efile_rename(Efile_error* errInfo, /* Where to return error codes. */ - char* src, /* Original name. */ - char* dst) /* New name. */ +efile_rename(Efile_error* errInfo, /* Where to return error codes. */ + char* src, /* Original name. */ + char* dst) /* New name. */ { - /* temporary fix AFM does not recognize ./ - * in destination */ - - char *dot_str; - if (dst != NULL) - { - dot_str = strchr(dst, '.'); + /* temporary fix AFM does not recognize ./ + * in destination remove pending on adaption of AFM fix + */ - if (dot_str && dot_str == dst && dot_str[1] == '/') - { - dst = dst+2; - } - } + char *dot_str; + if (dst != NULL) { + dot_str = strchr(dst, '.'); + if (dot_str && dot_str == dst && dot_str[1] == '/') { + dst = dst+2; + } + } - if (rename(src, dst) == 0) { - return 1; + if (rename(src, dst) == 0) { + return 1; } if (errno == ENOTEMPTY) { - errno = EEXIST; + errno = EEXIST; } -#if defined (sparc) - /* - * SunOS 4.1.4 reports overwriting a non-empty directory with a - * directory as EINVAL instead of EEXIST (first rule out the correct - * EINVAL result code for moving a directory into itself). Must be - * conditionally compiled because realpath() is only defined on SunOS. - */ - if (errno == EINVAL) { - char srcPath[MAXPATHLEN], dstPath[MAXPATHLEN]; - DIR *dirPtr; - struct dirent *dirEntPtr; - -#ifdef PURIFY - memset(srcPath, '\0', sizeof(srcPath)); - memset(dstPath, '\0', sizeof(dstPath)); -#endif + struct stat file_stat; - if ((realpath(src, srcPath) != NULL) - && (realpath(dst, dstPath) != NULL) - && (strncmp(srcPath, dstPath, strlen(srcPath)) != 0)) { - dirPtr = opendir(dst); - if (dirPtr != NULL) { - while ((dirEntPtr = readdir(dirPtr)) != NULL) { - if ((strcmp(dirEntPtr->d_name, ".") != 0) && - (strcmp(dirEntPtr->d_name, "..") != 0)) { - errno = EEXIST; - closedir(dirPtr); - return check_error(-1, errInfo); - } - } - closedir(dirPtr); - } - } - errno = EINVAL; + if (stat(dst, &file_stat)== 0) { + if (ISDIR(file_stat)) { + errno = EISDIR; + } + else if (ISREG(file_stat)) { + errno = ENOTDIR; + } + else { + errno = EINVAL; + } + } + else { + errno = EINVAL; + } } -#endif /* sparc */ if (strcmp(src, "/") == 0) { - /* - * Alpha reports renaming / as EBUSY and Linux reports it as EACCES, - * instead of EINVAL. - */ - - errno = EINVAL; + errno = EINVAL; } - - /* - * DEC Alpha OSF1 V3.0 returns EACCES when attempting to move a - * file across filesystems and the parent directory of that file is - * not writable. Most other systems return EXDEV. Does nothing to - * correct this behavior. - */ - return check_error(-1, errInfo); } +/***************************************************************************/ + int efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to make current. */ + char* name) /* Name of directory to make current. */ { return check_error(chdir(name), errInfo); } +/***************************************************************************/ int -efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ - int drive, /* 0 - current, 1 - A, 2 - B etc. */ - char* buffer, /* Where to return the current - directory. */ - size_t size) /* Size of buffer. */ +efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ + int drive, /* 0 - current, 1 - A, 2 - B etc. */ + char* buffer, /* Where to return the current + directory. */ + size_t size) /* Size of buffer. */ { if (drive == 0) { - if (getcwd(buffer, size) == NULL) - return check_error(-1, errInfo); - -#ifdef SIMSPARCSOLARIS - /* We get "host:" prepended to the dirname - remove!. */ - { - int i = 0; - int j = 0; - while ((buffer[i] != ':') && (buffer[i] != '\0')) i++; - if (buffer[i] == ':') { - i++; - while ((buffer[j++] = buffer[i++]) != '\0'); - } - } -#endif - return 1; + if (getcwd(buffer, size) == NULL) + return check_error(-1, errInfo); + + return 1; } /* @@ -475,29 +520,31 @@ efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ return check_error(-1, errInfo); } +/***************************************************************************/ + int -efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory - handle of - open directory.*/ - char* buffer, /* Pointer to buffer for - one filename. */ - size_t *size) /* in-out Size of buffer, length - of name. */ +efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory + handle of + open directory.*/ + char* buffer, /* Pointer to buffer for + one filename. */ + size_t *size) /* in-out Size of buffer, length + of name. */ { - DIR *dp; /* Pointer to directory structure. */ - struct dirent* dirp; /* Pointer to directory entry. */ + DIR *dp; /* Pointer to directory structure. */ + struct dirent* dirp; /* Pointer to directory entry. */ /* * If this is the first call, we must open the directory. */ if (*p_dir_handle == NULL) { - dp = opendir(name); - if (dp == NULL) - return check_error(-1, errInfo); - *p_dir_handle = (EFILE_DIR_HANDLE) dp; + dp = opendir(name); + if (dp == NULL) + return check_error(-1, errInfo); + *p_dir_handle = (EFILE_DIR_HANDLE) dp; } /* @@ -506,165 +553,138 @@ efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ dp = *((DIR **)((void *)p_dir_handle)); for (;;) { - dirp = readdir(dp); - if (dirp == NULL) { - closedir(dp); - return 0; - } - if (IS_DOT_OR_DOTDOT(dirp->d_name)) - continue; - buffer[0] = '\0'; - strncat(buffer, dirp->d_name, (*size)-1); - *size = strlen(dirp->d_name); - return 1; + dirp = readdir(dp); + if (dirp == NULL) { + closedir(dp); + return 0; + } + if (IS_DOT_OR_DOTDOT(dirp->d_name)) + continue; + buffer[0] = '\0'; + strncat(buffer, dirp->d_name, (*size)-1); + *size = strlen(dirp->d_name); + return 1; } } +/***************************************************************************/ + int -efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - int flags, /* Flags to user for opening. */ - int* pfd, /* Where to store the file - descriptor. */ - Sint64 *pSize) /* Where to store the size of the - file. */ +efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ + char* name, /* Name of directory to open. */ + int flags, /* Flags to user for opening. */ + int* pfd, /* Where to store the file + descriptor. */ + Sint64 *pSize) /* Where to store the size of the + file. */ { struct stat statbuf; int fd; - int mode; /* Open mode. */ + int mode; /* Open mode. */ if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { - /* - * For UNIX only, here is some ugly code to allow - * /dev/null to be opened as a file. - * - * Assumption: The i-node number for /dev/null cannot be zero. - */ - static ino_t dev_null_ino = 0; - - if (dev_null_ino == 0) { - struct stat nullstatbuf; - - if (stat("/dev/null", &nullstatbuf) >= 0) { - dev_null_ino = nullstatbuf.st_ino; - } - } - if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) { - errno = EISDIR; - return check_error(-1, errInfo); - } + errno = EISDIR; + return check_error(-1, errInfo); } switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { - case EFILE_MODE_READ: - mode = O_RDONLY; - break; - case EFILE_MODE_WRITE: - if (flags & EFILE_NO_TRUNCATE) - mode = O_WRONLY | O_CREAT; - else - mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case EFILE_MODE_READ_WRITE: - mode = O_RDWR | O_CREAT; - break; - default: - errno = EINVAL; - return check_error(-1, errInfo); + case EFILE_MODE_READ: + mode = O_RDONLY; + break; + case EFILE_MODE_WRITE: + if (flags & EFILE_NO_TRUNCATE) + mode = O_WRONLY | O_CREAT; + else + mode = O_WRONLY | O_CREAT | O_TRUNC; + break; + case EFILE_MODE_READ_WRITE: + mode = O_RDWR | O_CREAT; + break; + default: + errno = EINVAL; + return check_error(-1, errInfo); } if (flags & EFILE_MODE_APPEND) { - mode &= ~O_TRUNC; - mode |= O_APPEND; + mode &= ~O_TRUNC; + mode |= O_APPEND; } if (flags & EFILE_MODE_EXCL) { - mode |= O_EXCL; + mode |= O_EXCL; } fd = open(name, mode, FILE_MODE); if (!check_error(fd, errInfo)) - return 0; + return 0; *pfd = fd; if (pSize) { - *pSize = statbuf.st_size; + *pSize = statbuf.st_size; } return 1; } +/***************************************************************************/ + int efile_may_openfile(Efile_error* errInfo, char *name) { - struct stat statbuf; /* Information about the file */ + struct stat statbuf; /* Information about the file */ int result; result = stat(name, &statbuf); if (!check_error(result, errInfo)) - return 0; + return 0; if (!ISREG(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); + errno = EISDIR; + return check_error(-1, errInfo); } return 1; } +/***************************************************************************/ + void efile_closefile(int fd) { - if (L_FD_EXISTS(fd)) - { - free(fdm->fd_array[fd]); - fdm->fd_array[fd] = NULL; - } - close(fd); + if (l_find_local_fd(fd) != NULL) { + l_remove_local_fd(fd); + } + close(fd); } +/***************************************************************************/ + int efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync data. */ + int fd) /* File descriptor for file to sync data. */ { -#ifdef HAVE_FDATASYNC - return check_error(fdatasync(fd), errInfo); -#else return efile_fsync(errInfo, fd); -#endif } +/***************************************************************************/ + int efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync. */ + int fd) /* File descriptor for file to sync. */ { -#ifdef NO_FSYNC - undefined fsync /* XXX: Really? */ -#else -#if defined(DARWIN) && defined(F_FULLFSYNC) - return check_error(fcntl(fd, F_FULLFSYNC), errInfo); -#else return check_error(fsync(fd), errInfo); -#endif /* DARWIN */ -#endif /* NO_FSYNC */ } +/***************************************************************************/ + int efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, - char* name, int info_for_link) + char* name, int info_for_link) { - struct stat statbuf; /* Information about the file */ + struct stat statbuf; /* Information about the file */ int result; - if (info_for_link) { -#ifndef __OSE__ - result = lstat(name, &statbuf); -#else - result = stat(name, &statbuf); -#endif - } else { - result = stat(name, &statbuf); - } + result = stat(name, &statbuf); if (!check_error(result, errInfo)) { - return 0; + return 0; } #if SIZEOF_OFF_T == 4 @@ -682,22 +702,22 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, #else pInfo->access = FA_NONE; if (access(name, R_OK) == 0) - pInfo->access |= FA_READ; + pInfo->access |= FA_READ; if (access(name, W_OK) == 0) - pInfo->access |= FA_WRITE; + pInfo->access |= FA_WRITE; #endif if (ISDEV(statbuf)) - pInfo->type = FT_DEVICE; + pInfo->type = FT_DEVICE; else if (ISDIR(statbuf)) - pInfo->type = FT_DIRECTORY; + pInfo->type = FT_DIRECTORY; else if (ISREG(statbuf)) - pInfo->type = FT_REGULAR; + pInfo->type = FT_REGULAR; else if (ISLNK(statbuf)) - pInfo->type = FT_SYMLINK; + pInfo->type = FT_SYMLINK; else - pInfo->type = FT_OTHER; + pInfo->type = FT_OTHER; pInfo->accessTime = statbuf.st_atime; pInfo->modifyTime = statbuf.st_mtime; @@ -706,9 +726,6 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, pInfo->mode = statbuf.st_mode; pInfo->links = statbuf.st_nlink; pInfo->major_device = statbuf.st_dev; -#ifndef __OSE__ - pInfo->minor_device = statbuf.st_rdev; -#endif pInfo->inode = statbuf.st_ino; pInfo->uid = statbuf.st_uid; pInfo->gid = statbuf.st_gid; @@ -716,205 +733,164 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, return 1; } +/***************************************************************************/ + int efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { -/* FIXME, this will be dificult to get to work right with the tests on ose - * reason being that the info values are sometimes used in different ways, and in - * some times not used at all. */ - -#ifndef __OSE__ - struct utimbuf tval; -#endif - /* * On some systems chown will always fail for a non-root user unless * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as * you don't try to chown a file to someone besides youself. */ -#ifndef __OSE__ - if (chown(name, pInfo->uid, pInfo->gid) && errno != EPERM) { - return check_error(-1, errInfo); - } -#endif - if (pInfo->mode != -1) { - mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | - S_IRWXU | S_IRWXG | S_IRWXO); - if (chmod(name, newMode)) { - newMode &= ~(S_ISUID | S_ISGID); - if (chmod(name, newMode)) { - return check_error(-1, errInfo); - } - } + mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | + S_IRWXU | S_IRWXG | S_IRWXO); + if (chmod(name, newMode)) { + newMode &= ~(S_ISUID | S_ISGID); + if (chmod(name, newMode)) { + return check_error(-1, errInfo); + } + } } -#ifndef __OSE__ - tval.actime = pInfo->accessTime; - tval.modtime = pInfo->modifyTime; - - return check_error(utime(name, &tval), errInfo); -#else - return 1; -#endif + return 1; } +/***************************************************************************/ int -efile_write(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was - opened. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count) /* Number of bytes to write. */ +efile_write(Efile_error* errInfo, /* Where to return error codes. */ + int flags, /* Flags given when file was + opened. */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count) /* Number of bytes to write. */ { - ssize_t written; /* Bytes written in last operation. */ - - if (L_FD_EXISTS(fd)) - { - off_t off; - off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); - - if (L_FD_OFFSET_BEYOND_EOF(fd, off)) - { - l_pad_file(fd, off); - } - - L_FD_INVALIDATE(fd); - } - - while (count > 0) - { - if ((written = write(fd, buf, count)) < 0) - { - if (errno != EINTR) - { - return check_error(-1, errInfo); - } - else - { - written = 0; - } - } - ASSERT(written <= count); - buf += written; - count -= written; + ssize_t written; /* Bytes written in last operation. */ + struct fd_data *fd_data; + + if ((fd_data = l_find_local_fd(fd)) != NULL) { + if (L_FD_IS_VALID(fd_data)) { + /* we are beyond eof and need to pad*/ + if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { + return check_error(-1, errInfo); + } + } } - if (L_FD_EXISTS(fd)) - { - L_FD_INVALIDATE(fd); + while (count > 0) { + if ((written = write(fd, buf, count)) < 0) { + if (errno != EINTR) { + return check_error(-1, errInfo); + } + else { + written = 0; + } + } + ASSERT(written <= count); + buf += written; + count -= written; } return 1; } +/***************************************************************************/ + int efile_writev(Efile_error* errInfo, /* Where to return error codes */ - int flags, /* Flags given when file was - * opened */ - int fd, /* File descriptor to write to */ - SysIOVec* iov, /* Vector of buffer structs. - * The structs may be changed i.e. - * due to incomplete writes */ - int iovcnt) /* Number of structs in vector */ + int flags, /* Flags given when file was + * opened */ + int fd, /* File descriptor to write to */ + SysIOVec* iov, /* Vector of buffer structs. + * The structs may be changed i.e. + * due to incomplete writes */ + int iovcnt) /* Number of structs in vector */ { + struct fd_data *fd_data; int cnt = 0; /* Buffers so far written */ ASSERT(iovcnt >= 0); - + if ((fd_data = l_find_local_fd(fd)) != NULL) { + if (L_FD_IS_VALID(fd_data)) { + /* we are beyond eof and need to pad*/ + if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { + return check_error(-1, errInfo); + } + } + } while (cnt < iovcnt) { - if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { - /* Empty buffer - skip */ - cnt++; - } else { /* Non-empty buffer */ - ssize_t w; /* Bytes written in this call */ -#ifdef HAVE_WRITEV - int b = iovcnt - cnt; /* Buffers to write */ - /* Use as many buffers as MAXIOV allows */ - if (b > MAXIOV) - b = MAXIOV; - if (b > 1) { - do { - w = writev(fd, &iov[cnt], b); - } while (w < 0 && errno == EINTR); - } else - /* Degenerated io vector - use regular write */ -#endif - { - do { - w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); - } while (w < 0 && errno == EINTR); - ASSERT(w <= iov[cnt].iov_len || w == -1); - } - if (w < 0) return check_error(-1, errInfo); - /* Move forward to next buffer to write */ - for (; cnt < iovcnt && w > 0; cnt++) { - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - if (w < iov[cnt].iov_len) { - /* Adjust the buffer for next write */ - iov[cnt].iov_len -= w; - iov[cnt].iov_base += w; - w = 0; - break; - } else { - w -= iov[cnt].iov_len; - } - } - } - ASSERT(w == 0); - } /* else Non-empty buffer */ + if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { + /* Empty buffer - skip */ + cnt++; + } + else { /* Non-empty buffer */ + ssize_t w; /* Bytes written in this call */ + do { + w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + } while (w < 0 && errno == EINTR); + + ASSERT(w <= iov[cnt].iov_len || w == -1); + + if (w < 0) { + return check_error(-1, errInfo); + } + /* Move forward to next buffer to write */ + for (; cnt < iovcnt && w > 0; cnt++) { + if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { + if (w < iov[cnt].iov_len) { + /* Adjust the buffer for next write */ + iov[cnt].iov_len -= w; + iov[cnt].iov_base += w; + w = 0; + break; + } + else { + w -= iov[cnt].iov_len; + } + } + } + ASSERT(w == 0); + } /* else Non-empty buffer */ } /* while (cnt< iovcnt) */ return 1; } +/***************************************************************************/ + int efile_read(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was opened. */ - int fd, /* File descriptor to read from. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return number of - bytes read. */ + int flags, /* Flags given when file was opened. */ + int fd, /* File descriptor to read from. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return number of + bytes read. */ { ssize_t n; - if (L_FD_EXISTS(fd)) - { - off_t off; - off = (L_FD_IS_VALID(fd)) ? L_FD_CUR(fd) : lseek(fd, 0, SEEK_CUR); - if (L_FD_IS_VALID(fd) == 0) - { - l_update_local_fd(fd, off, SEEK_SET); - } - - if (L_FD_OFFSET_BEYOND_EOF(fd, off)) - { - *pBytesRead = 0; - return 1; - } - /* FIXME .. is this needed? */ - lseek(fd, off, SEEK_SET); - } - - for (;;) - { - if ((n = read(fd, buf, count)) >= 0) - { - break; - } - else if (errno != EINTR) - { - return check_error(-1, errInfo); - } + struct fd_data *fd_data; + + if ((fd_data = l_find_local_fd(fd)) != NULL) { + if (L_FD_IS_VALID(fd_data)) { + *pBytesRead = 0; + return 1; + } } - if (n != 0 && L_FD_EXISTS(fd)) - { - L_FD_INVALIDATE(fd); + for (;;) { + if ((n = read(fd, buf, count)) >= 0) { + break; + } + else if (errno != EINTR) { + return check_error(-1, errInfo); + } + } + if (fd_data != NULL && L_FD_IS_VALID(fd_data)) { + L_FD_INVALIDATE(fd_data); } *pBytesRead = (size_t) n; return 1; } - /* pread() and pwrite() */ /* Some unix systems, notably Solaris has these syscalls */ /* It is especially nice for i.e. the dets module to have support */ @@ -928,198 +904,159 @@ efile_read(Efile_error* errInfo, /* Where to return error codes. */ int efile_pread(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to read from. */ - Sint64 offset, /* Offset in bytes from BOF. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return - number of bytes read. */ + int fd, /* File descriptor to read from. */ + Sint64 offset, /* Offset in bytes from BOF. */ + char* buf, /* Buffer to read into. */ + size_t count, /* Number of bytes to read. */ + size_t *pBytesRead) /* Where to return + number of bytes read. */ { -#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) - ssize_t n; - off_t off = (off_t) offset; - if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); - } - for (;;) { - if ((n = pread(fd, buf, count, offset)) >= 0) - break; - else if (errno != EINTR) - return check_error(-1, errInfo); - } - *pBytesRead = (size_t) n; - return 1; -#else - { - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - if (res) { - return efile_read(errInfo, 0, fd, buf, count, pBytesRead); - } else { - return res; - } + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + if (res) { + return efile_read(errInfo, 0, fd, buf, count, pBytesRead); + } else { + return res; } -#endif } +/***************************************************************************/ int efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count, /* Number of bytes to write. */ - Sint64 offset) /* where to write it */ + int fd, /* File descriptor to write to. */ + char* buf, /* Buffer to write. */ + size_t count, /* Number of bytes to write. */ + Sint64 offset) /* where to write it */ { -#if defined(HAVE_PREAD) && defined(HAVE_PWRITE) - ssize_t written; /* Bytes written in last operation. */ - off_t off = (off_t) offset; - if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); - } - - while (count > 0) { - if ((written = pwrite(fd, buf, count, offset)) < 0) { - if (errno != EINTR) - return check_error(-1, errInfo); - else - written = 0; - } - ASSERT(written <= count); - buf += written; - count -= written; - offset += written; - } - return 1; -#else /* For unix systems that don't support pread() and pwrite() */ - { - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); + int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - if (res) { - return efile_write(errInfo, 0, fd, buf, count); - } else { - return res; - } + if (res) { + return efile_write(errInfo, 0, fd, buf, count); + } else { + return res; } -#endif } +/***************************************************************************/ int efile_seek(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to do the seek on. */ - Sint64 offset, /* Offset in bytes from the given - origin. */ - int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, - SEEK_END). */ - Sint64 *new_location) /* Resulting new location in file. */ + int fd, /* File descriptor to do the seek on. */ + Sint64 offset, /* Offset in bytes from the given + origin. */ + int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, + SEEK_END). */ + Sint64 *new_location) /* Resulting new location in file. */ { off_t off, result; off = (off_t) offset; switch (origin) { - case EFILE_SEEK_SET: origin = SEEK_SET; break; - case EFILE_SEEK_CUR: origin = SEEK_CUR; break; - case EFILE_SEEK_END: origin = SEEK_END; break; - default: - errno = EINVAL; - return check_error(-1, errInfo); + case EFILE_SEEK_SET: + origin = SEEK_SET; + break; + case EFILE_SEEK_CUR: + origin = SEEK_CUR; + break; + case EFILE_SEEK_END: + origin = SEEK_END; + break; + default: + errno = EINVAL; + return check_error(-1, errInfo); } + if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); + errno = EINVAL; + return check_error(-1, errInfo); } errno = 0; result = lseek(fd, off, origin); - if (result >= 0 && L_FD_EXISTS(fd)) - { - L_FD_INVALIDATE(fd); + if (result >= 0) { + l_invalidate_local_fd(fd); } - /* - * Note that the man page for lseek (on SunOs 5) says: - * - * "if fildes is a remote file descriptor and offset is - * negative, lseek() returns the file pointer even if it is - * negative." - */ + if (result < 0) + { + if (errno == ENOSYS) { + int size, cur_pos; + + if (off < 0) { + errno = EINVAL; + return check_error(-1, errInfo); + } + + cur_pos = lseek(fd, 0, SEEK_CUR); + size = lseek(fd, 0, SEEK_END); + + if (origin == SEEK_SET) { + result = offset; + } + else if (origin == SEEK_CUR) { + result = offset + cur_pos; + } + else if (origin == SEEK_END) { + result = size + offset; + } - if (result < 0 && errno == 0) - errno = EINVAL; - if (result < 0) - { - /* Some filesystems on OSE does not handle seeking beyond EOF - * We handle this here, by localy storing offsets. */ - - if ((lseek(fd, 0, SEEK_END) < off) && errno == 78) - { - if (fdm == NULL) /* first time */ - { - if (l_init_local_fd() == -1) - { - errno = EINVAL; - check_error(-1, errInfo); - } + /* sanity check our result */ + if (size > result) { + return check_error(-1, errInfo); } - l_update_local_fd(fd, off, origin); - result = off; - } - else if (off < 0 && errno == ENOSYS) - { + + /* store the data localy */ + l_update_local_fd(fd, result, size); + + /* reset the original file position */ + if (origin != SEEK_END) { + lseek(fd, cur_pos, SEEK_SET); + } + } + else if (errno == 0) { errno = EINVAL; - return check_error(-1, errInfo); - } - else - { - return check_error(-1, errInfo); - } - } - if (new_location) { - *new_location = result; - } - return 1; + } + } + + if (new_location) { + *new_location = result; + } + + return 1; } +/***************************************************************************/ int efile_truncate_file(Efile_error* errInfo, int *fd, int flags) { -#ifndef NO_FTRUNCATE off_t offset; + struct fd_data *fd_data; - if (L_FD_EXISTS(fileno(fd))) - { - L_FD_INVALIDATE(fileno(fd)); + if ((fd_data = l_find_local_fd(*fd)) != NULL && L_FD_IS_VALID(fd_data)) { + offset = L_FD_CUR(fd_data); + } + else { + offset = lseek(*fd, 0, SEEK_CUR); } - return check_error((offset = lseek(*fd, 0, SEEK_CUR)) >= 0 && - ftruncate(*fd, offset) == 0 ? 1 : -1, errInfo); -#else - return 1; -#endif + return check_error(((offset >= 0) && + (ftruncate(*fd, offset) == 0)) ? 1 : -1, errInfo); } +/***************************************************************************/ + int efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) { -#ifndef __OSE__ - int len; - ASSERT(size > 0); - len = readlink(name, buffer, size-1); - if (len == -1) { - return check_error(-1, errInfo); - } - buffer[len] = '\0'; - return 1; -#else errno = ENOTSUP; return check_error(-1, errInfo); -#endif } +/***************************************************************************/ + int efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) { @@ -1127,158 +1064,35 @@ efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) return check_error(-1, errInfo); } +/***************************************************************************/ + int efile_link(Efile_error* errInfo, char* old, char* new) { -#ifndef __OSE__ - return check_error(link(old, new), errInfo); -#else errno = ENOTSUP; return check_error(-1, errInfo); -#endif } +/***************************************************************************/ + int efile_symlink(Efile_error* errInfo, char* old, char* new) { -#ifndef __OSE__ - return check_error(symlink(old, new), errInfo); -#else errno = ENOTSUP; return check_error(-1, errInfo); -#endif } +/***************************************************************************/ + int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, - Sint64 length, int advise) + Sint64 length, int advise) { -#ifdef HAVE_POSIX_FADVISE return check_error(posix_fadvise(fd, offset, length, advise), errInfo); -#else - return check_error(0, errInfo); -#endif } -#ifdef HAVE_SENDFILE -/* For some reason the maximum size_t cannot be used as the max size - 3GB seems to work on all platforms */ -#define SENDFILE_CHUNK_SIZE ((1UL << 30) -1) - -/* - * sendfile: The implementation of the sendfile system call varies - * a lot on different *nix platforms so to make the api similar in all - * we have to emulate some things in linux and play with variables on - * bsd/darwin. - * - * All of the calls will split a command which tries to send more than - * SENDFILE_CHUNK_SIZE of data at once. - * - * On platforms where *nbytes of 0 does not mean the entire file, this is - * simulated. - * - * It could be possible to implement header/trailer in sendfile. Though - * you would have to emulate it in linux and on BSD/Darwin some complex - * calculations have to be made when using a non blocking socket to figure - * out how much of the header/file/trailer was sent in each command. - * - * The semantics of the API is this: - * Return value: 1 if all data was sent and the function does not need to - * be called again. 0 if an error occures OR if there is more data which - * has to be sent (EAGAIN or EINTR will be set appropriately) - * - * The amount of data written in a call is returned through nbytes. - * - */ - -int -efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, - off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl* hdtl) -{ - Uint64 written = 0; -#if defined(__linux__) - ssize_t retval; - do { - /* check if *nbytes is 0 or greater than chunk size */ - if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) - retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE); - else - retval = sendfile(out_fd, in_fd, offset, *nbytes); - if (retval > 0) { - written += retval; - *nbytes -= retval; - } - } while (retval == SENDFILE_CHUNK_SIZE); - if (written != 0) { - /* -1 is not returned by the linux API so we have to simulate it */ - retval = -1; - errno = EAGAIN; - } -#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) - ssize_t retval; - size_t len; - sendfilevec_t fdrec; - fdrec.sfv_fd = in_fd; - fdrec.sfv_flag = 0; - do { - fdrec.sfv_off = *offset; - len = 0; - /* check if *nbytes is 0 or greater than chunk size */ - if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) - fdrec.sfv_len = SENDFILE_CHUNK_SIZE; - else - fdrec.sfv_len = *nbytes; - retval = sendfilev(out_fd, &fdrec, 1, &len); - - /* Sometimes sendfilev can return -1 and still send data. - When that happens we just pretend that no error happend. */ - if (retval != -1 || errno == EAGAIN || errno == EINTR || - len != 0) { - *offset += len; - *nbytes -= len; - written += len; - if (errno != EAGAIN && errno != EINTR && len != 0) - retval = len; - } - } while (len == SENDFILE_CHUNK_SIZE); -#elif defined(DARWIN) - int retval; - off_t len; - do { - /* check if *nbytes is 0 or greater than chunk size */ - if(*nbytes > SENDFILE_CHUNK_SIZE) - len = SENDFILE_CHUNK_SIZE; - else - len = *nbytes; - retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0); - if (retval != -1 || errno == EAGAIN || errno == EINTR) { - *offset += len; - *nbytes -= len; - written += len; - } - } while (len == SENDFILE_CHUNK_SIZE); -#elif defined(__FreeBSD__) || defined(__DragonFly__) - off_t len; - int retval; - do { - if (*nbytes > SENDFILE_CHUNK_SIZE) - retval = sendfile(in_fd, out_fd, *offset, SENDFILE_CHUNK_SIZE, - NULL, &len, 0); - else - retval = sendfile(in_fd, out_fd, *offset, *nbytes, NULL, &len, 0); - if (retval != -1 || errno == EAGAIN || errno == EINTR) { - *offset += len; - *nbytes -= len; - written += len; - } - } while(len == SENDFILE_CHUNK_SIZE); -#endif - *nbytes = written; - return check_error(retval, errInfo); -} -#endif /* HAVE_SENDFILE */ +/***************************************************************************/ -#ifdef HAVE_POSIX_FALLOCATE static int call_posix_fallocate(int fd, Sint64 offset, Sint64 length) { @@ -1300,58 +1114,11 @@ call_posix_fallocate(int fd, Sint64 offset, Sint64 length) return ret; } -#endif /* HAVE_POSIX_FALLOCATE */ + +/***************************************************************************/ int efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) { -#if defined HAVE_FALLOCATE - /* Linux specific, more efficient than posix_fallocate. */ - int ret; - - do { - ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, (off_t) offset, (off_t) length); - } while (ret != 0 && errno == EINTR); - -#if defined HAVE_POSIX_FALLOCATE - /* Fallback to posix_fallocate if available. */ - if (ret != 0) { - ret = call_posix_fallocate(fd, offset, length); - } -#endif - - return check_error(ret, errInfo); -#elif defined F_PREALLOCATE - /* Mac OS X specific, equivalent to posix_fallocate. */ - int ret; - fstore_t fs; - - memset(&fs, 0, sizeof(fs)); - fs.fst_flags = F_ALLOCATECONTIG; - fs.fst_posmode = F_VOLPOSMODE; - fs.fst_offset = (off_t) offset; - fs.fst_length = (off_t) length; - - ret = fcntl(fd, F_PREALLOCATE, &fs); - - if (-1 == ret) { - fs.fst_flags = F_ALLOCATEALL; - ret = fcntl(fd, F_PREALLOCATE, &fs); - -#if defined HAVE_POSIX_FALLOCATE - /* Fallback to posix_fallocate if available. */ - if (-1 == ret) { - ret = call_posix_fallocate(fd, offset, length); - } -#endif - } - - return check_error(ret, errInfo); -#elif defined HAVE_POSIX_FALLOCATE - /* Other Unixes, use posix_fallocate if available. */ return check_error(call_posix_fallocate(fd, offset, length), errInfo); -#else - errno = ENOTSUP; - return check_error(-1, errInfo); -#endif } diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 8ffc05da99..06078858ca 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -101,6 +101,11 @@ check_error(int result, Efile_error *errInfo) return 1; } +int +efile_init() { + return 1; +} + int efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ char* name) /* Name of directory to create. */ diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index d693d7d593..480ba23239 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -196,6 +196,11 @@ set_error(Efile_error* errInfo) return 0; } +int +efile_init() { + return 1; +} + /* * A writev with Unix semantics, but with Windows arguments */ -- cgit v1.2.3 From 2145db903b665622ea885db175c5e606d9f840a4 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 22 Nov 2013 09:50:34 +0100 Subject: ose: OSE port related cleanup and fixes Some OSE cross-chains have problems with system includes being used, so for atleast OSE specific parts we use "" instead of <>. --- erts/emulator/drivers/common/efile_drv.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 7ef985dc41..b62e9a0306 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -99,7 +99,16 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif + +#ifndef __OSE__ +#include +#include #include +#else +#include "ctype.h" +#include "sys/types.h" +#include "stdlib.h" +#endif /* Need (NON)BLOCKING macros for sendfile */ #ifndef WANT_NONBLOCKING @@ -113,8 +122,7 @@ #include "erl_threads.h" #include "gzio.h" #include "dtrace-wrapper.h" -#include -#include + void erl_exit(int n, char *fmt, ...); -- cgit v1.2.3 From c64851d619fb916362abc8db9c28534eff39f53c Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 10 Jan 2014 17:17:58 +0100 Subject: ose: Rewrite resolve_signal API for ose drivers This new API has less impact on the check_io code and also removes the callback from ErlDrvEntry. The downside is that you have to give the resolve function when creating each event. Also the mode if the resolve was removed as this mimics the win32 code and decreases complexity. --- erts/emulator/drivers/ose/ose_signal_drv.c | 41 +++++++++++++++++------------- 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index c1d861cc5a..46890a1503 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -392,6 +392,19 @@ static int drv_init(void) { return 0; } +/* Signal resolution callback */ +static ErlDrvOseEventId resolve_signal(union SIGNAL* osig) { + union SIGNAL *sig = osig; + if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || + sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { + return sig->async.spid; + } + DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", + current_process(),sig->signo,addressee(&sig),sender(&sig)); + return addressee(&sig); +} + + /** * Start routine for the driver **/ @@ -488,11 +501,13 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) DEBUGP("0x%x: open\n",ctxt->spid); ctxt->perm_events[1] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid); + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid, + resolve_signal); driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); ctxt->perm_events[0] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid); + erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid, + resolve_signal); driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); start(ctxt->spid); @@ -669,7 +684,8 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) EV_GET_UINT32(ev,&signo,&p,&q); } else if (signo < tmp_signo || !ctxt->events) { /* New signal to select on */ - events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid); + events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid, + resolve_signal); driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); EV_GET_UINT32(ev,&signo,&p,&q); } else { @@ -708,7 +724,7 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) { driver_context_t *ctxt = (driver_context_t *)driver_data; - union SIGNAL *sig = erl_drv_ose_get_input_signal(event); + union SIGNAL *sig = erl_drv_ose_get_signal(event); while (sig != NULL) { @@ -800,7 +816,7 @@ static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) } free_buf(&sig); - sig = erl_drv_ose_get_input_signal(event); + sig = erl_drv_ose_get_signal(event); } } @@ -858,17 +874,6 @@ static void stop_select(ErlDrvEvent event, void *reserved) erl_drv_ose_event_free(event); } -static int resolve_signal(OseSignal* osig, int *mode) { - union SIGNAL *sig = osig; - if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || - sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { - return sig->async.spid; - } - DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", - current_process(),sig->signo,addressee(&sig),sender(&sig)); - return addressee(&sig); -} - /** * Setup the driver entry for the Erlang runtime **/ @@ -884,6 +889,6 @@ ErlDrvEntry ose_signal_driver_entry = { .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING, - .stop_select = stop_select, - .resolve_signal = resolve_signal + .stop_select = stop_select }; + -- cgit v1.2.3 From a35d0f5f82f8152f1b953eda039807a7d4f4e9b9 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Sun, 23 Feb 2014 18:26:38 +0100 Subject: ose: Thread priorities configurable from lmconf The pattern used for getting the priority from the lmconf is based on the name of the process created. The pattern is: ERTS_%%PROCESS_NAME%%_PRIO with the %%PROCESS_NAME%% replaced by the prefix of the process the priority applies to. eg: ERTS_SCHEDULER_PRIO=24 applies to processes with name SCHEDULER_1, SCHEDULER_2 etc. --- erts/emulator/drivers/ose/ose_signal_drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index 46890a1503..1335bffe18 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -29,6 +29,7 @@ #include "erl_driver.h" #include "ose.h" + #ifdef HAVE_OSE_SPI_H #include "ose_spi/ose_spi.h" #endif @@ -363,6 +364,7 @@ static OS_PROCESS(driver_proxy_process) { } } + /** * Init routine for the driver **/ -- cgit v1.2.3 From 4a6850e522b91eb009ddd0ed9d9f542f1baf1bee Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 21 Feb 2014 14:01:38 +0100 Subject: ose: Updating event and signal API for OSE --- erts/emulator/drivers/ose/ose_signal_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c index 1335bffe18..4929b53856 100644 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ b/erts/emulator/drivers/ose/ose_signal_drv.c @@ -504,12 +504,12 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) ctxt->perm_events[1] = erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid, - resolve_signal); + resolve_signal, NULL); driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); ctxt->perm_events[0] = erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid, - resolve_signal); + resolve_signal, NULL); driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); start(ctxt->spid); @@ -679,7 +679,7 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) { if (ctxt->events) - erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL); + erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL,NULL); if (signo == tmp_signo) { events[i++] = ctxt->events[j++]; @@ -687,7 +687,7 @@ static void outputv(ErlDrvData driver_data, ErlIOVec *ev) } else if (signo < tmp_signo || !ctxt->events) { /* New signal to select on */ events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid, - resolve_signal); + resolve_signal, NULL); driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); EV_GET_UINT32(ev,&signo,&p,&q); } else { -- cgit v1.2.3 From 08910c59fb8dda35ee3c272d84cba450954fcd24 Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Fri, 21 Feb 2014 15:19:31 +0100 Subject: ose: Add dummy ttsl driver --- erts/emulator/drivers/ose/ttsl_drv.c | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 erts/emulator/drivers/ose/ttsl_drv.c (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/ose/ttsl_drv.c b/erts/emulator/drivers/ose/ttsl_drv.c new file mode 100644 index 0000000000..8af2ce6af3 --- /dev/null +++ b/erts/emulator/drivers/ose/ttsl_drv.c @@ -0,0 +1,68 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2013. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Stub tty driver because group/user depend on this. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "erl_driver.h" + +static int ttysl_init(void); +static ErlDrvData ttysl_start(ErlDrvPort, char*); + +/* Define the driver table entry. */ +struct erl_drv_entry ttsl_driver_entry = { + ttysl_init, + ttysl_start, + NULL, + NULL, + NULL, + NULL, + "tty_sl", + NULL, + NULL, + NULL, + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, /* ERL_DRV_FLAGs */ + NULL, + NULL, /* process_exit */ + NULL +}; + + +static int ttysl_init(void) +{ + return 0; +} + +static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) +{ + return ERL_DRV_ERROR_GENERAL; +} -- cgit v1.2.3 From 81abbc48e12317a07a8d2fcc041031c1c1567c8d Mon Sep 17 00:00:00 2001 From: Lukas Larsson Date: Mon, 24 Feb 2014 09:43:11 +0100 Subject: erts: Fix unix efile assert If writev return an error (eg ENOSPC) we do not want to abort here but instead propagate upwards into erlang. --- erts/emulator/drivers/unix/unix_efile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/emulator/drivers') diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06078858ca..42f41c5f3d 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -634,7 +634,8 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ do { w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); } while (w < 0 && errno == EINTR); - ASSERT(w <= iov[cnt].iov_len); + ASSERT(w <= iov[cnt].iov_len || + (w == -1 && errno != EINTR)); } if (w < 0) return check_error(-1, errInfo); /* Move forward to next buffer to write */ -- cgit v1.2.3