aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/common/efile_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers/common/efile_drv.c')
-rw-r--r--erts/emulator/drivers/common/efile_drv.c104
1 files changed, 73 insertions, 31 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 15b6c5a17f..b132991a3b 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -104,6 +104,7 @@
#ifndef WANT_NONBLOCKING
#define WANT_NONBLOCKING
#endif
+
#include "sys.h"
#include "erl_driver.h"
@@ -147,6 +148,22 @@ static ErlDrvSysInfo sys_info;
#define MUTEX_UNLOCK(m)
#endif
+
+/**
+ * On DARWIN sendfile can deadlock with close if called in
+ * different threads. So until Apple fixes so that sendfile
+ * is not buggy we disable usage of the async pool for
+ * DARWIN. The testcase t_sendfile_crashduring reproduces
+ * this error when using +A 10.
+ */
+#if !defined(DARWIN)
+#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0)
+#else
+#define USE_THRDS_FOR_SENDFILE 0
+#endif /* !DARWIN */
+
+
+
#if 0
/* Experimental, for forcing all file operations to use the same thread. */
static unsigned file_fixed_key = 1;
@@ -735,6 +752,15 @@ file_stop(ErlDrvData e)
TRACE_C('p');
+#ifdef HAVE_SENDFILE
+ if (desc->sendfile_state == sending && !USE_THRDS_FOR_SENDFILE) {
+ driver_select(desc->port,(ErlDrvEvent)(long)desc->d->c.sendfile.out_fd,
+ ERL_DRV_WRITE|ERL_DRV_USE,0);
+ } else if (desc->sendfile_state == sending) {
+ SET_NONBLOCKING(desc->d->c.sendfile.out_fd);
+ }
+#endif /* HAVE_SENDFILE */
+
if (desc->fd != FILE_FD_INVALID) {
do_close(desc->flags, desc->fd);
desc->fd = FILE_FD_INVALID;
@@ -800,7 +826,16 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num,
driver_output2(desc->port, response, t-response, NULL, 0);
}
+static void reply_string_error(file_descriptor *desc, char* str) {
+ char response[256]; /* Response buffer. */
+ char* s;
+ char* t;
+ response[0] = FILE_RESP_ERROR;
+ for (s = str, t = response+1; *s; s++, t++)
+ *t = tolower(*s);
+ driver_output2(desc->port, response, t-response, NULL, 0);
+}
static int reply_error(file_descriptor *desc,
Efile_error *errInfo) /* The error codes. */
@@ -1745,7 +1780,7 @@ static void invoke_sendfile(void *data)
d->c.sendfile.written += nbytes;
if (result == 1) {
- if (sys_info.async_threads != 0) {
+ if (USE_THRDS_FOR_SENDFILE) {
d->result_ok = 0;
} else if (d->c.sendfile.nbytes == 0 && nbytes != 0) {
d->result_ok = 1;
@@ -2121,24 +2156,25 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
if (d->result_ok) {
resbuf[0] = FILE_RESP_INFO;
- put_int32(d->info.size_high, &resbuf[1 + (0 * 4)]);
- put_int32(d->info.size_low, &resbuf[1 + (1 * 4)]);
- put_int32(d->info.type, &resbuf[1 + (2 * 4)]);
-
- PUT_TIME(d->info.accessTime, resbuf + 1 + 3*4);
- PUT_TIME(d->info.modifyTime, resbuf + 1 + 9*4);
- PUT_TIME(d->info.cTime, resbuf + 1 + 15*4);
-
- put_int32(d->info.mode, &resbuf[1 + (21 * 4)]);
- put_int32(d->info.links, &resbuf[1 + (22 * 4)]);
- put_int32(d->info.major_device, &resbuf[1 + (23 * 4)]);
- put_int32(d->info.minor_device, &resbuf[1 + (24 * 4)]);
- put_int32(d->info.inode, &resbuf[1 + (25 * 4)]);
- put_int32(d->info.uid, &resbuf[1 + (26 * 4)]);
- put_int32(d->info.gid, &resbuf[1 + (27 * 4)]);
- put_int32(d->info.access, &resbuf[1 + (28 * 4)]);
-
-#define RESULT_SIZE (1 + (29 * 4))
+ put_int32(d->info.size_high, &resbuf[1 + ( 0 * 4)]);
+ put_int32(d->info.size_low, &resbuf[1 + ( 1 * 4)]);
+ put_int32(d->info.type, &resbuf[1 + ( 2 * 4)]);
+
+ /* Note 64 bit indexing in resbuf here */
+ put_int64(d->info.accessTime, &resbuf[1 + ( 3 * 4)]);
+ put_int64(d->info.modifyTime, &resbuf[1 + ( 5 * 4)]);
+ put_int64(d->info.cTime, &resbuf[1 + ( 7 * 4)]);
+
+ put_int32(d->info.mode, &resbuf[1 + ( 9 * 4)]);
+ put_int32(d->info.links, &resbuf[1 + (10 * 4)]);
+ put_int32(d->info.major_device, &resbuf[1 + (11 * 4)]);
+ put_int32(d->info.minor_device, &resbuf[1 + (12 * 4)]);
+ put_int32(d->info.inode, &resbuf[1 + (13 * 4)]);
+ put_int32(d->info.uid, &resbuf[1 + (14 * 4)]);
+ put_int32(d->info.gid, &resbuf[1 + (15 * 4)]);
+ put_int32(d->info.access, &resbuf[1 + (16 * 4)]);
+
+#define RESULT_SIZE (1 + (17 * 4))
TRACE_C('R');
driver_output2(desc->port, resbuf, RESULT_SIZE, NULL, 0);
#undef RESULT_SIZE
@@ -2209,8 +2245,13 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
case FILE_SENDFILE:
if (d->result_ok == -1) {
desc->sendfile_state = not_sending;
- reply_error(desc, &d->errInfo);
- if (sys_info.async_threads != 0) {
+ if (d->errInfo.posix_errno == ECONNRESET ||
+ d->errInfo.posix_errno == ENOTCONN ||
+ d->errInfo.posix_errno == EPIPE)
+ reply_string_error(desc,"closed");
+ else
+ reply_error(desc, &d->errInfo);
+ if (USE_THRDS_FOR_SENDFILE) {
SET_NONBLOCKING(d->c.sendfile.out_fd);
free_sendfile(data);
} else {
@@ -2221,7 +2262,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
} else if (d->result_ok == 0) {
desc->sendfile_state = not_sending;
reply_Sint64(desc, d->c.sendfile.written);
- if (sys_info.async_threads != 0) {
+ if (USE_THRDS_FOR_SENDFILE) {
SET_NONBLOCKING(d->c.sendfile.out_fd);
free_sendfile(data);
} else {
@@ -2486,15 +2527,16 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
case FILE_WRITE_INFO:
{
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1
- + FILENAME_BYTELEN(buf+21*4) + FILENAME_CHARSIZE);
+ + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE);
- d->info.mode = get_int32(buf + 0 * 4);
- d->info.uid = get_int32(buf + 1 * 4);
- d->info.gid = get_int32(buf + 2 * 4);
- GET_TIME(d->info.accessTime, buf + 3 * 4);
- GET_TIME(d->info.modifyTime, buf + 9 * 4);
- GET_TIME(d->info.cTime, buf + 15 * 4);
- FILENAME_COPY(d->b, buf+21*4);
+ d->info.mode = get_int32(buf + 0 * 4);
+ d->info.uid = get_int32(buf + 1 * 4);
+ d->info.gid = get_int32(buf + 2 * 4);
+ d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4));
+ d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4));
+ d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4));
+
+ FILENAME_COPY(d->b, buf + 9*4);
d->command = command;
d->invoke = invoke_write_info;
d->free = free_data;
@@ -3426,7 +3468,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->c.sendfile.nbytes = nbytes;
- if (sys_info.async_threads != 0) {
+ if (USE_THRDS_FOR_SENDFILE) {
SET_BLOCKING(d->c.sendfile.out_fd);
}