aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/unix
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/drivers/unix')
-rw-r--r--erts/emulator/drivers/unix/bin_drv.c21
-rw-r--r--erts/emulator/drivers/unix/multi_drv.c23
-rw-r--r--erts/emulator/drivers/unix/sig_drv.c21
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c200
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c41
5 files changed, 232 insertions, 74 deletions
diff --git a/erts/emulator/drivers/unix/bin_drv.c b/erts/emulator/drivers/unix/bin_drv.c
index 1827187d57..21fb398907 100644
--- a/erts/emulator/drivers/unix/bin_drv.c
+++ b/erts/emulator/drivers/unix/bin_drv.c
@@ -3,16 +3,17 @@
*
* Copyright Ericsson AB 1996-2009. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
diff --git a/erts/emulator/drivers/unix/multi_drv.c b/erts/emulator/drivers/unix/multi_drv.c
index 822c96730c..7f8c2d9a0d 100644
--- a/erts/emulator/drivers/unix/multi_drv.c
+++ b/erts/emulator/drivers/unix/multi_drv.c
@@ -3,16 +3,17 @@
*
* Copyright Ericsson AB 1996-2009. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
@@ -20,7 +21,7 @@
/* Purpose: Multidriver interface
This is an example of a driver which allows multiple instances of itself.
I.e have one erlang process execute open_port(multi......) and
- at the same time have an other erlang process open an other port
+ at the same time have another erlang process open another port
running multi there as well.
*/
diff --git a/erts/emulator/drivers/unix/sig_drv.c b/erts/emulator/drivers/unix/sig_drv.c
index aab5d63a40..e6f2ecc494 100644
--- a/erts/emulator/drivers/unix/sig_drv.c
+++ b/erts/emulator/drivers/unix/sig_drv.c
@@ -3,16 +3,17 @@
*
* Copyright Ericsson AB 1996-2009. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index 491e0a090e..25cad37e25 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -3,16 +3,17 @@
*
* 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/.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * 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.
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
@@ -32,6 +33,10 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*);
#ifdef HAVE_TERMCAP /* else make an empty driver that can not be opened */
+#ifndef WANT_NONBLOCKING
+#define WANT_NONBLOCKING
+#endif
+
#include "sys.h"
#include <ctype.h>
#include <stdlib.h>
@@ -39,6 +44,7 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*);
#include <string.h>
#include <signal.h>
#include <fcntl.h>
+#include <limits.h>
#include <locale.h>
#include <unistd.h>
#include <termios.h>
@@ -57,6 +63,14 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*);
#include <langinfo.h>
#endif
+#if defined IOV_MAX
+#define MAXIOV IOV_MAX
+#elif defined UIO_MAXIOV
+#define MAXIOV UIO_MAXIOV
+#else
+#define MAXIOV 16
+#endif
+
#define TRUE 1
#define FALSE 0
@@ -80,12 +94,15 @@ static volatile int cols_needs_update = FALSE;
#define OP_INSC 2
#define OP_DELC 3
#define OP_BEEP 4
+#define OP_PUTC_SYNC 5
/* Control op */
#define CTRL_OP_GET_WINSIZE 100
#define CTRL_OP_GET_UNICODE_STATE 101
#define CTRL_OP_SET_UNICODE_STATE 102
-
+/* We use 1024 as the buf size as that was the default buf size of FILE streams
+ on all platforms that I checked. */
+#define TTY_BUFFSIZE 1024
static int lbuf_size = BUFSIZ;
static Uint32 *lbuf; /* The current line buffer */
@@ -113,13 +130,19 @@ static int lpos; /* The current "cursor position" in the line buf
/* Main interface functions. */
static void ttysl_stop(ErlDrvData);
static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT);
+static void ttysl_to_tty(ErlDrvData, ErlDrvEvent);
+static void ttysl_flush_tty(ErlDrvData);
static void ttysl_from_tty(ErlDrvData, ErlDrvEvent);
static void ttysl_stop_select(ErlDrvEvent, void*);
static Sint16 get_sint16(char*);
static ErlDrvPort ttysl_port;
static int ttysl_fd;
-static FILE *ttysl_out;
+static int ttysl_terminate = 0;
+static int ttysl_send_ok = 0;
+static ErlDrvBinary *putcbuf;
+static int putcpos;
+static int putclen;
/* Functions that work on the line buffer. */
static int start_lbuf(void);
@@ -201,22 +224,22 @@ struct erl_drv_entry ttsl_driver_entry = {
IF_IMPL(ttysl_stop),
IF_IMPL(ttysl_from_erlang),
IF_IMPL(ttysl_from_tty),
- NULL,
- "tty_sl",
- NULL,
- NULL,
+ IF_IMPL(ttysl_to_tty),
+ "tty_sl", /* driver_name */
+ NULL, /* finish */
+ NULL, /* handle */
IF_IMPL(ttysl_control),
NULL, /* timeout */
NULL, /* outputv */
NULL, /* ready_async */
- NULL, /* flush */
+ IF_IMPL(ttysl_flush_tty),
NULL, /* call */
NULL, /* event */
ERL_DRV_EXTENDED_MARKER,
ERL_DRV_EXTENDED_MAJOR_VERSION,
ERL_DRV_EXTENDED_MINOR_VERSION,
0, /* ERL_DRV_FLAGs */
- NULL,
+ NULL, /* handle2 */
NULL, /* process_exit */
IF_IMPL(ttysl_stop_select)
};
@@ -296,8 +319,7 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf)
return ERL_DRV_ERROR_GENERAL;
}
- /* Open the terminal and set the terminal */
- ttysl_out = fdopen(ttysl_fd, "w");
+ SET_NONBLOCKING(ttysl_fd);
#ifdef PRIMITIVE_UTF8_CHECK
setlocale(LC_CTYPE, ""); /* Set international environment,
@@ -317,8 +339,8 @@ static ErlDrvData ttysl_start(ErlDrvPort port, char* buf)
}
#endif
DEBUGLOG(("utf8_mode is %s\n",(utf8_mode) ? "on" : "off"));
- sys_sigset(SIGCONT, cont);
- sys_sigset(SIGWINCH, winch);
+ sys_signal(SIGCONT, cont);
+ sys_signal(SIGWINCH, winch);
driver_select(port, (ErlDrvEvent)(UWord)ttysl_fd, ERL_DRV_READ|ERL_DRV_USE, 1);
ttysl_port = port;
@@ -400,12 +422,14 @@ static void ttysl_stop(ErlDrvData ttysl_data)
stop_lbuf();
stop_termcap();
tty_reset(ttysl_fd);
- driver_select(ttysl_port, (ErlDrvEvent)(UWord)ttysl_fd, ERL_DRV_READ|ERL_DRV_USE, 0);
- sys_sigset(SIGCONT, SIG_DFL);
- sys_sigset(SIGWINCH, SIG_DFL);
+ driver_select(ttysl_port, (ErlDrvEvent)(UWord)ttysl_fd,
+ ERL_DRV_WRITE|ERL_DRV_READ|ERL_DRV_USE, 0);
+ sys_signal(SIGCONT, SIG_DFL);
+ sys_signal(SIGWINCH, SIG_DFL);
}
ttysl_port = (ErlDrvPort)-1;
ttysl_fd = -1;
+ ttysl_terminate = 0;
/* return TRUE; */
}
@@ -650,10 +674,26 @@ static int check_buf_size(byte *s, int n)
static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count)
{
+ ErlDrvSizeT sz;
+
+ sz = driver_sizeq(ttysl_port);
+
+ putclen = count > TTY_BUFFSIZE ? TTY_BUFFSIZE : count;
+ putcbuf = driver_alloc_binary(putclen);
+ putcpos = 0;
+
if (lpos > MAXSIZE)
put_chars((byte*)"\n", 1);
switch (buf[0]) {
+ case OP_PUTC_SYNC:
+ /* Using sync means that we have to send an ok to the
+ controlling process for each command call. We delay
+ sending ok if the driver queue exceeds a certain size.
+ We do not set ourselves as a busy port, as this
+ could be very bad for user_drv, if it gets blocked on
+ the port_command. */
+ /* fall through */
case OP_PUTC:
DEBUGLOG(("OP: Putc(%lu)",(unsigned long) count-1));
if (check_buf_size((byte*)buf+1, count-1) == 0)
@@ -678,10 +718,106 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun
/* Unknown op, just ignore. */
break;
}
- fflush(ttysl_out);
+
+ driver_enq_bin(ttysl_port,putcbuf,0,putcpos);
+ driver_free_binary(putcbuf);
+
+ if (sz == 0) {
+ for (;;) {
+ int written, qlen;
+ SysIOVec *iov;
+
+ iov = driver_peekq(ttysl_port,&qlen);
+ if (iov)
+ written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen);
+ else
+ written = 0;
+ if (written < 0) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
+ driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd,
+ ERL_DRV_USE|ERL_DRV_WRITE,1);
+ break;
+ } else {
+ driver_failure_posix(ttysl_port, errno);
+ return;
+ }
+ } else {
+ if (driver_deq(ttysl_port, written) == 0)
+ break;
+ }
+ }
+ }
+
+ if (buf[0] == OP_PUTC_SYNC) {
+ if (driver_sizeq(ttysl_port) > TTY_BUFFSIZE && !ttysl_terminate) {
+ /* We delay sending the ack until the buffer has been consumed */
+ ttysl_send_ok = 1;
+ } else {
+ ErlDrvTermData spec[] = {
+ ERL_DRV_PORT, driver_mk_port(ttysl_port),
+ ERL_DRV_ATOM, driver_mk_atom("ok"),
+ ERL_DRV_TUPLE, 2
+ };
+ ASSERT(ttysl_send_ok == 0);
+ erl_drv_output_term(driver_mk_port(ttysl_port), spec,
+ sizeof(spec) / sizeof(spec[0]));
+ }
+ }
+
return; /* TRUE; */
}
+static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) {
+ for (;;) {
+ int written, qlen;
+ SysIOVec *iov;
+ ErlDrvSizeT sz;
+
+ iov = driver_peekq(ttysl_port,&qlen);
+ if (iov)
+ written = writev(ttysl_fd, iov, qlen > MAXIOV ? MAXIOV : qlen);
+ else
+ written = 0;
+ if (written < 0) {
+ if (errno == EINTR) {
+ continue;
+ } else if (errno != ERRNO_BLOCK){
+ driver_failure_posix(ttysl_port, errno);
+ }
+ break;
+ } else {
+ sz = driver_deq(ttysl_port, written);
+ if (sz < TTY_BUFFSIZE && ttysl_send_ok) {
+ ErlDrvTermData spec[] = {
+ ERL_DRV_PORT, driver_mk_port(ttysl_port),
+ ERL_DRV_ATOM, driver_mk_atom("ok"),
+ ERL_DRV_TUPLE, 2
+ };
+ ttysl_send_ok = 0;
+ erl_drv_output_term(driver_mk_port(ttysl_port), spec,
+ sizeof(spec) / sizeof(spec[0]));
+ }
+ if (sz == 0) {
+ driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd,
+ ERL_DRV_WRITE,0);
+ if (ttysl_terminate)
+ /* flush has been called, which means we should terminate
+ when queue is empty. This will not send any exit
+ message */
+ driver_failure_atom(ttysl_port, "normal");
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+static void ttysl_flush_tty(ErlDrvData ttysl_data) {
+ ttysl_terminate = 1;
+ return;
+}
+
static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd)
{
byte b[1024];
@@ -1070,7 +1206,15 @@ static int write_buf(Uint32 *s, int n)
/* The basic procedure for outputting one character. */
static int outc(int c)
{
- return (int)putc(c, ttysl_out);
+ putcbuf->orig_bytes[putcpos++] = c;
+ if (putcpos == putclen) {
+ driver_enq_bin(ttysl_port,putcbuf,0,putclen);
+ driver_free_binary(putcbuf);
+ putcpos = 0;
+ putclen = TTY_BUFFSIZE;
+ putcbuf = driver_alloc_binary(BUFSIZ);
+ }
+ return 1;
}
static int move_cursor(int from, int to)
@@ -1318,11 +1462,11 @@ static RETSIGTYPE suspend(int sig)
exit(1);
}
- sys_sigset(sig, SIG_DFL); /* Set signal handler to default */
+ sys_signal(sig, SIG_DFL); /* Set signal handler to default */
sys_sigrelease(sig); /* Allow 'sig' to come through */
kill(getpid(), sig); /* Send ourselves the signal */
sys_sigblock(sig); /* Reset to old mask */
- sys_sigset(sig, suspend); /* Reset signal handler */
+ sys_signal(sig, suspend); /* Reset signal handler */
if (tty_set(ttysl_fd) < 0) {
fprintf(stderr,"Can't set tty raw \n");
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 42f41c5f3d..00da48b107 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -3,16 +3,17 @@
*
* Copyright Ericsson AB 1997-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/.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * 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.
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
@@ -38,16 +39,21 @@
#ifdef HAVE_SYS_UIO_H
#include <sys/types.h>
#include <sys/uio.h>
+#if defined(HAVE_SENDFILE) && (defined(__FreeBSD__) || defined(__DragonFly__))
+/* Need to define __BSD_VISIBLE in order to expose prototype of sendfile */
+#define __BSD_VISIBLE 1
+#include <sys/socket.h>
+#endif
#endif
#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4)))
#include <sys/sendfile.h>
#endif
#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
-#define DARWIN 1
+#define __DARWIN__ 1
#endif
-#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE)
+#if defined(__DARWIN__) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE)
#include <fcntl.h>
#endif
@@ -360,7 +366,12 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
int fd;
int mode; /* Open mode. */
- if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) {
+ if (stat(name, &statbuf) < 0) {
+ /* statbuf is undefined: if the caller depends on it,
+ i.e. invoke_read_file(), fail the call immediately */
+ if (pSize && flags == EFILE_MODE_READ)
+ return check_error(-1, errInfo);
+ } else if (!ISREG(statbuf)) {
/*
* For UNIX only, here is some ugly code to allow
* /dev/null to be opened as a file.
@@ -470,11 +481,11 @@ efile_fsync(Efile_error *errInfo, /* Where to return error codes. */
#ifdef NO_FSYNC
undefined fsync /* XXX: Really? */
#else
-#if defined(DARWIN) && defined(F_FULLFSYNC)
+#if defined(__DARWIN__) && defined(F_FULLFSYNC)
return check_error(fcntl(fd, F_FULLFSYNC), errInfo);
#else
return check_error(fsync(fd), errInfo);
-#endif /* DARWIN */
+#endif /* __DARWIN__ */
#endif /* NO_FSYNC */
}
@@ -956,7 +967,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
retval = len;
}
} while (len == SENDFILE_CHUNK_SIZE);
-#elif defined(DARWIN)
+#elif defined(__DARWIN__)
int retval;
off_t len;
do {