1017
1033
/* Driver interfaces */
1018
1034
static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*);
1019
1035
static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*);
1020
static int fd_control(ErlDrvData, unsigned int, char *, int, char **, int);
1036
static ErlDrvSSizeT fd_control(ErlDrvData, unsigned int, char *, ErlDrvSizeT,
1037
char **, ErlDrvSizeT);
1021
1038
static ErlDrvData vanilla_start(ErlDrvPort, char*, SysDriverOpts*);
1022
1039
static int spawn_init(void);
1023
1040
static void fd_stop(ErlDrvData);
1024
1041
static void stop(ErlDrvData);
1025
1042
static void ready_input(ErlDrvData, ErlDrvEvent);
1026
1043
static void ready_output(ErlDrvData, ErlDrvEvent);
1027
static void output(ErlDrvData, char*, int);
1044
static void output(ErlDrvData, char*, ErlDrvSizeT);
1028
1045
static void outputv(ErlDrvData, ErlIOVec*);
1029
1046
static void stop_select(ErlDrvEvent, void*);
2312
2306
close((int)fd);
2316
** Async opertation support
2318
#if defined(USE_THREADS) && !defined(ERTS_SMP)
2320
sys_async_ready_failed(int fd, int r, int err)
2323
sprintf(buf, "sys_async_ready(): Fatal error: fd=%d, r=%d, errno=%d\n",
2325
erts_silence_warn_unused_result(write(2, buf, strlen(buf)));
2329
/* called from threads !! */
2330
void sys_async_ready(int fd)
2334
r = write(fd, "0", 1); /* signal main thread fd MUST be async_fd[1] */
2336
DEBUGF(("sys_async_ready(): r = 1\r\n"));
2339
if (r < 0 && errno == EINTR) {
2340
DEBUGF(("sys_async_ready(): r = %d\r\n", r));
2343
sys_async_ready_failed(fd, r, errno);
2347
static int async_drv_init(void)
2354
static ErlDrvData async_drv_start(ErlDrvPort port_num,
2355
char* name, SysDriverOpts* opts)
2357
if (async_fd[0] != -1)
2358
return ERL_DRV_ERROR_GENERAL;
2359
if (pipe(async_fd) < 0)
2360
return ERL_DRV_ERROR_GENERAL;
2362
DEBUGF(("async_drv_start: %d\r\n", port_num));
2364
SET_NONBLOCKING(async_fd[0]);
2365
driver_select(port_num, async_fd[0], ERL_DRV_READ, 1);
2367
if (init_async(async_fd[1]) < 0)
2368
return ERL_DRV_ERROR_GENERAL;
2369
return (ErlDrvData)port_num;
2372
static void async_drv_stop(ErlDrvData e)
2374
int port_num = (int)(long)e;
2376
DEBUGF(("async_drv_stop: %d\r\n", port_num));
2380
driver_select(port_num, async_fd[0], ERL_DRV_READ, 0);
2384
async_fd[0] = async_fd[1] = -1;
2388
static void async_drv_input(ErlDrvData e, ErlDrvEvent fd)
2391
DEBUGF(("async_drv_input\r\n"));
2392
while (read((int) fd, (void *) buf, 32) > 0); /* fd MUST be async_fd[0] */
2393
check_async_ready(); /* invoke all async_ready */
2397
2310
void erts_do_break_handling(void)
2500
2416
fd_data = (struct fd_data *)
2501
2417
erts_alloc(ERTS_ALC_T_FD_TAB, max_files * sizeof(struct fd_data));
2502
erts_smp_atomic_add(&sys_misc_mem_sz,
2503
max_files * sizeof(struct fd_data));
2507
if (init_async(-1) < 0)
2508
erl_exit(1, "Failed to initialize async-threads\n");
2511
/* This is speical stuff, starting a driver from the
2512
* system routines, but is a nice way of handling stuff
2515
SysDriverOpts dopts;
2518
sys_memset((void*)&dopts, 0, sizeof(SysDriverOpts));
2519
add_driver_entry(&async_driver_entry);
2520
ret = erts_open_driver(NULL, NIL, "async", &dopts, NULL);
2521
DEBUGF(("open_driver = %d\n", ret));
2523
erl_exit(1, "Failed to open async driver\n");
2524
erts_port[ret].status |= ERTS_PORT_SFLG_IMMORTAL;
2418
erts_smp_atomic_add_nob(&sys_misc_mem_sz,
2419
max_files * sizeof(struct fd_data));
2531
2422
#if (0) /* unused? */
2917
2791
* to other threads.
2919
2793
* NOTE 2: The signal dispatcher thread is not a blockable
2920
* thread (i.e., it hasn't called
2921
* erts_register_blockable_thread()). This is
2922
* intentional. We want to be able to interrupt
2923
* writing of a crash dump by hitting C-c twice.
2924
* Since it isn't a blockable thread it is important
2925
* that it doesn't change the state of any data that
2926
* a blocking thread expects to have exclusive access
2927
* to (unless the signal dispatcher itself explicitly
2928
* is blocking all blockable threads).
2794
* thread (i.e., not a thread managed by the
2795
* erl_thr_progress module). This is intentional.
2796
* We want to be able to interrupt writing of a crash
2797
* dump by hitting C-c twice. Since it isn't a
2798
* blockable thread it is important that it doesn't
2799
* change the state of any data that a blocking thread
2800
* expects to have exclusive access to (unless the
2801
* signal dispatcher itself explicitly is blocking all
2802
* blockable threads).
2930
2804
switch (buf[i]) {
2931
2805
case 0: /* Emulator initialized */
2932
2807
initialized = 1;
2934
2808
if (!notify_check_children)
3108
3022
argv[j++] = argv[i];
3113
#ifdef ERTS_TIMER_THREAD
3116
* Interruptible-wait facility: low-level synchronisation state
3117
* and methods that are implementation dependent.
3119
* Constraint: Every implementation must define 'struct erts_iwait'
3120
* with a field 'erts_smp_atomic_t state;'.
3123
/* values for struct erts_iwait's state field */
3124
#define IWAIT_WAITING 0
3125
#define IWAIT_AWAKE 1
3126
#define IWAIT_INTERRUPT 2
3128
#if 0 /* XXX: needs feature test in erts/configure.in */
3131
* This is an implementation of the interruptible wait facility on
3132
* top of Linux-specific futexes.
3134
#include <asm/unistd.h>
3135
#define FUTEX_WAIT 0
3136
#define FUTEX_WAKE 1
3137
static int sys_futex(void *futex, int op, int val, const struct timespec *timeout)
3139
return syscall(__NR_futex, futex, op, val, timeout);
3143
erts_smp_atomic_t state; /* &state.counter is our futex */
3146
static void iwait_lowlevel_init(struct erts_iwait *iwait) { /* empty */ }
3148
static void iwait_lowlevel_wait(struct erts_iwait *iwait, struct timeval *delay)
3150
struct timespec timeout;
3153
timeout.tv_sec = delay->tv_sec;
3154
timeout.tv_nsec = delay->tv_usec * 1000;
3155
res = sys_futex((void*)&iwait->state.counter, FUTEX_WAIT, IWAIT_WAITING, &timeout);
3156
if (res < 0 && errno != ETIMEDOUT && errno != EWOULDBLOCK && errno != EINTR)
3157
perror("FUTEX_WAIT");
3160
static void iwait_lowlevel_interrupt(struct erts_iwait *iwait)
3162
int res = sys_futex((void*)&iwait->state.counter, FUTEX_WAKE, 1, NULL);
3164
perror("FUTEX_WAKE");
3167
#else /* using poll() or select() */
3170
* This is an implementation of the interruptible wait facility on
3171
* top of pipe(), poll() or select(), read(), and write().
3174
erts_smp_atomic_t state;
3175
int read_fd; /* wait polls and reads this fd */
3176
int write_fd; /* interrupt writes this fd */
3179
static void iwait_lowlevel_init(struct erts_iwait *iwait)
3183
if (pipe(fds) < 0) {
3187
iwait->read_fd = fds[0];
3188
iwait->write_fd = fds[1];
3191
#if defined(ERTS_USE_POLL)
3193
#include <sys/poll.h>
3194
#define PERROR_POLL "poll()"
3196
static int iwait_lowlevel_poll(int read_fd, struct timeval *delay)
3198
struct pollfd pollfd;
3201
pollfd.fd = read_fd;
3202
pollfd.events = POLLIN;
3204
timeout = delay->tv_sec * 1000 + delay->tv_usec / 1000;
3205
return poll(&pollfd, 1, timeout);
3208
#else /* !ERTS_USE_POLL */
3210
#include <sys/select.h>
3211
#define PERROR_POLL "select()"
3213
static int iwait_lowlevel_poll(int read_fd, struct timeval *delay)
3218
FD_SET(read_fd, &readfds);
3219
return select(read_fd + 1, &readfds, NULL, NULL, delay);
3222
#endif /* !ERTS_USE_POLL */
3224
static void iwait_lowlevel_wait(struct erts_iwait *iwait, struct timeval *delay)
3229
res = iwait_lowlevel_poll(iwait->read_fd, delay);
3231
(void)read(iwait->read_fd, buf, sizeof buf);
3232
else if (res < 0 && errno != EINTR)
3233
perror(PERROR_POLL);
3236
static void iwait_lowlevel_interrupt(struct erts_iwait *iwait)
3238
int res = write(iwait->write_fd, "!", 1);
3243
#endif /* using poll() or select() */
3245
#if 0 /* not using poll() or select() */
3247
* This is an implementation of the interruptible wait facility on
3248
* top of pthread_cond_timedwait(). This has two problems:
3249
* 1. pthread_cond_timedwait() requires an absolute time point,
3250
* so the relative delay must be converted to absolute time.
3251
* Worse, this breaks if the machine's time is adjusted while
3252
* we're preparing to wait.
3253
* 2. Each cond operation requires additional mutex lock/unlock operations.
3255
* Problem 2 is probably not too bad on Linux (they'll just become
3256
* relatively cheap futex operations), but problem 1 is the real killer.
3257
* Only use this implementation if no better alternatives are available!
3260
erts_smp_atomic_t state;
3261
pthread_cond_t cond;
3262
pthread_mutex_t mutex;
3265
static void iwait_lowlevel_init(struct erts_iwait *iwait)
3267
iwait->cond = (pthread_cond_t) PTHREAD_COND_INITIALIZER;
3268
iwait->mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
3271
static void iwait_lowlevel_wait(struct erts_iwait *iwait, struct timeval *delay)
3274
struct timespec timeout;
3276
/* Due to pthread_cond_timedwait()'s use of absolute
3277
time, this must be the real gettimeofday(), _not_
3278
the "smoothed" one beam/erl_time_sup.c implements. */
3279
gettimeofday(&tmp, NULL);
3281
tmp.tv_sec += delay->tv_sec;
3282
tmp.tv_usec += delay->tv_usec;
3283
if (tmp.tv_usec >= 1000*1000) {
3284
tmp.tv_usec -= 1000*1000;
3287
timeout.tv_sec = tmp.tv_sec;
3288
timeout.tv_nsec = tmp.tv_usec * 1000;
3289
pthread_mutex_lock(&iwait->mutex);
3290
pthread_cond_timedwait(&iwait->cond, &iwait->mutex, &timeout);
3291
pthread_mutex_unlock(&iwait->mutex);
3294
static void iwait_lowlevel_interrupt(struct erts_iwait *iwait)
3296
pthread_mutex_lock(&iwait->mutex);
3297
pthread_cond_signal(&iwait->cond);
3298
pthread_mutex_unlock(&iwait->mutex);
3301
#endif /* not using POLL */
3304
* Interruptible-wait facility. This is just a wrapper around the
3305
* low-level synchronisation code, where we maintain our logical
3306
* state in order to suppress some state transitions.
3309
struct erts_iwait *erts_iwait_init(void)
3311
struct erts_iwait *iwait = malloc(sizeof *iwait);
3316
iwait_lowlevel_init(iwait);
3317
erts_smp_atomic_init(&iwait->state, IWAIT_AWAKE);
3321
void erts_iwait_wait(struct erts_iwait *iwait, struct timeval *delay)
3323
if (erts_smp_atomic_xchg(&iwait->state, IWAIT_WAITING) != IWAIT_INTERRUPT)
3324
iwait_lowlevel_wait(iwait, delay);
3325
erts_smp_atomic_set(&iwait->state, IWAIT_AWAKE);
3328
void erts_iwait_interrupt(struct erts_iwait *iwait)
3330
if (erts_smp_atomic_xchg(&iwait->state, IWAIT_INTERRUPT) == IWAIT_WAITING)
3331
iwait_lowlevel_interrupt(iwait);
3334
#endif /* ERTS_TIMER_THREAD */