diff options
Diffstat (limited to 'erts/emulator/sys/unix/sys.c')
-rw-r--r-- | erts/emulator/sys/unix/sys.c | 127 |
1 files changed, 80 insertions, 47 deletions
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index c485a4eece..0b96eded76 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -123,7 +123,8 @@ struct ErtsSysReportExit_ { /* This data is shared by these drivers - initialized by spawn_init() */ static struct driver_data { - int port_num, ofd, packet_bytes; + ErlDrvPort port_num; + int ofd, packet_bytes; ErtsSysReportExit *report_exit; int pid; int alive; @@ -577,7 +578,7 @@ erl_sys_init(void) + 1); child_setup_prog = erts_alloc(ERTS_ALC_T_CS_PROG_PATH, csp_path_sz); erts_smp_atomic_add_nob(&sys_misc_mem_sz, csp_path_sz); - sprintf(child_setup_prog, + erts_snprintf(child_setup_prog, csp_path_sz, "%s%c%s", bindir, DIR_SEPARATOR_CHAR, @@ -686,7 +687,7 @@ static RETSIGTYPE break_handler(int sig) } #endif /* 0 */ -static ERTS_INLINE void +static ERTS_INLINE int prepare_crash_dump(int secs) { #define NUFBUF (3) @@ -698,24 +699,41 @@ prepare_crash_dump(int secs) Eterm *hp = heap; Eterm list = NIL; int heart_fd[2] = {-1,-1}; + int has_heart = 0; UseTmpHeapNoproc(NUFBUF); if (ERTS_PREPARED_CRASH_DUMP) - return; /* We have already been called */ + return 0; /* We have already been called */ heart_port = erts_get_heart_port(); + + /* Positive secs means an alarm must be set + * 0 or negative means no alarm + * + * Set alarm before we try to write to a port + * we don't want to hang on a port write with + * no alarm. + * + */ + + if (secs >= 0) { + alarm((unsigned int)secs); + } + if (heart_port) { /* hearts input fd * We "know" drv_data is the in_fd since the port is started with read|write */ heart_fd[0] = (int)heart_port->drv_data; heart_fd[1] = (int)driver_data[heart_fd[0]].ofd; + has_heart = 1; list = CONS(hp, make_small(8), list); hp += 2; /* send to heart port, CMD = 8, i.e. prepare crash dump =o */ - erts_write_to_port(ERTS_INVALID_PID, heart_port, list); + erts_port_output(NULL, ERTS_PORT_SIG_FLG_FORCE_IMM_CALL, heart_port, + heart_port->common.id, list, NULL); } /* Make sure we unregister at epmd (unknown fd) and get at least @@ -752,20 +770,14 @@ prepare_crash_dump(int secs) erts_silence_warn_unused_result(nice(nice_val)); } - /* Positive secs means an alarm must be set - * 0 or negative means no alarm - */ - if (secs > 0) { - alarm((unsigned int)secs); - } UnUseTmpHeapNoproc(NUFBUF); #undef NUFBUF + return has_heart; } -void -erts_sys_prepare_crash_dump(int secs) +int erts_sys_prepare_crash_dump(int secs) { - prepare_crash_dump(secs); + return prepare_crash_dump(secs); } static ERTS_INLINE void @@ -802,12 +814,22 @@ static RETSIGTYPE request_break(int signum) static ERTS_INLINE void sigusr1_exit(void) { - /* We do this at interrupt level, since the main reason for - wanting to generate a crash dump in this way is that the emulator - is hung somewhere, so it won't be able to poll any flag we set here. - */ + char env[21]; /* enough to hold any 64-bit integer */ + size_t envsz; + int i, secs = -1; + + /* We do this at interrupt level, since the main reason for + * wanting to generate a crash dump in this way is that the emulator + * is hung somewhere, so it won't be able to poll any flag we set here. + */ ERTS_SET_GOT_SIGUSR1; - prepare_crash_dump((int)0); + + envsz = sizeof(env); + if ((i = erts_sys_getenv_raw("ERL_CRASH_DUMP_SECONDS", env, &envsz)) >= 0) { + secs = i != 0 ? 0 : atoi(env); + } + + prepare_crash_dump(secs); erl_exit(1, "Received SIGUSR1\n"); } @@ -1162,7 +1184,7 @@ static RETSIGTYPE onchld(int signum) #endif } -static int set_driver_data(int port_num, +static int set_driver_data(ErlDrvPort port_num, int ifd, int ofd, int packet_bytes, @@ -1170,6 +1192,7 @@ static int set_driver_data(int port_num, int exit_status, int pid) { + Port *prt; ErtsSysReportExit *report_exit; if (!exit_status) @@ -1178,7 +1201,7 @@ static int set_driver_data(int port_num, report_exit = erts_alloc(ERTS_ALC_T_PRT_REP_EXIT, sizeof(ErtsSysReportExit)); report_exit->next = report_exit_list; - report_exit->port = erts_port[port_num].id; + report_exit->port = erts_drvport2id(port_num); report_exit->pid = pid; report_exit->ifd = read_write & DO_READ ? ifd : -1; report_exit->ofd = read_write & DO_WRITE ? ofd : -1; @@ -1188,7 +1211,9 @@ static int set_driver_data(int port_num, report_exit_list = report_exit; } - erts_port[port_num].os_pid = pid; + prt = erts_drvport2port(port_num, NULL); + if (prt) + prt->os_pid = pid; if (read_write & DO_READ) { driver_data[ifd].packet_bytes = packet_bytes; @@ -1261,7 +1286,7 @@ static void close_pipes(int ifd[2], int ofd[2], int read_write) } } -static void init_fd_data(int fd, int prt) +static void init_fd_data(int fd, ErlDrvPort port_num) { fd_data[fd].buf = NULL; fd_data[fd].cpos = NULL; @@ -1557,12 +1582,13 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op } #if !DISABLE_VFORK } +#define ENOUGH_BYTES (44) else { /* Use vfork() */ char **cs_argv= erts_alloc(ERTS_ALC_T_TMP,(CS_ARGV_NO_OF_ARGS + 1)* sizeof(char *)); - char fd_close_range[44]; /* 44 bytes are enough to */ - char dup2_op[CS_ARGV_NO_OF_DUP2_OPS][44]; /* hold any "%d:%d" string */ - /* on a 64-bit machine. */ + char fd_close_range[ENOUGH_BYTES]; /* 44 bytes are enough to */ + char dup2_op[CS_ARGV_NO_OF_DUP2_OPS][ENOUGH_BYTES]; /* hold any "%d:%d" string */ + /* on a 64-bit machine. */ /* Setup argv[] for the child setup program (implemented in erl_child_setup.c) */ @@ -1570,23 +1596,23 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op if (opts->use_stdio) { if (opts->read_write & DO_READ){ /* stdout for process */ - sprintf(&dup2_op[i++][0], "%d:%d", ifd[1], 1); + erts_snprintf(&dup2_op[i++][0], ENOUGH_BYTES, "%d:%d", ifd[1], 1); if(opts->redir_stderr) /* stderr for process */ - sprintf(&dup2_op[i++][0], "%d:%d", ifd[1], 2); + erts_snprintf(&dup2_op[i++][0], ENOUGH_BYTES, "%d:%d", ifd[1], 2); } if (opts->read_write & DO_WRITE) /* stdin for process */ - sprintf(&dup2_op[i++][0], "%d:%d", ofd[0], 0); + erts_snprintf(&dup2_op[i++][0], ENOUGH_BYTES, "%d:%d", ofd[0], 0); } else { /* XXX will fail if ofd[0] == 4 (unlikely..) */ if (opts->read_write & DO_READ) - sprintf(&dup2_op[i++][0], "%d:%d", ifd[1], 4); + erts_snprintf(&dup2_op[i++][0], ENOUGH_BYTES, "%d:%d", ifd[1], 4); if (opts->read_write & DO_WRITE) - sprintf(&dup2_op[i++][0], "%d:%d", ofd[0], 3); + erts_snprintf(&dup2_op[i++][0], ENOUGH_BYTES, "%d:%d", ofd[0], 3); } for (; i < CS_ARGV_NO_OF_DUP2_OPS; i++) strcpy(&dup2_op[i][0], "-"); - sprintf(fd_close_range, "%d:%d", opts->use_stdio ? 3 : 5, max_files-1); + erts_snprintf(fd_close_range, ENOUGH_BYTES, "%d:%d", opts->use_stdio ? 3 : 5, max_files-1); cs_argv[CS_ARGV_PROGNAME_IX] = child_setup_prog; cs_argv[CS_ARGV_WD_IX] = opts->wd ? opts->wd : "."; @@ -1637,6 +1663,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op } erts_free(ERTS_ALC_T_TMP,cs_argv); } +#undef ENOUGH_BYTES #endif erts_sched_bind_atfork_parent(unbind); @@ -1949,7 +1976,7 @@ static void clear_fd_data(int fd) fd_data[fd].psz = 0; } -static void nbio_stop_fd(int prt, int fd) +static void nbio_stop_fd(ErlDrvPort prt, int fd) { driver_select(prt,fd,DO_READ|DO_WRITE,0); clear_fd_data(fd); @@ -1997,7 +2024,8 @@ static ErlDrvData vanilla_start(ErlDrvPort port_num, char* name, static void stop(ErlDrvData fd) { - int prt, ofd; + ErlDrvPort prt; + int ofd; prt = driver_data[(int)(long)fd].port_num; nbio_stop_fd(prt, (int)(long)fd); @@ -2010,7 +2038,7 @@ static void stop(ErlDrvData fd) CHLD_STAT_LOCK; - /* Mark as unused. Maybe resetting the 'port_num' slot is better? */ + /* Mark as unused. */ driver_data[(int)(long)fd].pid = -1; CHLD_STAT_UNLOCK; @@ -2026,7 +2054,7 @@ static void stop(ErlDrvData fd) static void outputv(ErlDrvData e, ErlIOVec* ev) { int fd = (int)(long)e; - int ix = driver_data[fd].port_num; + ErlDrvPort ix = driver_data[fd].port_num; int pb = driver_data[fd].packet_bytes; int ofd = driver_data[fd].ofd; ssize_t n; @@ -2076,7 +2104,7 @@ static void outputv(ErlDrvData e, ErlIOVec* ev) static void output(ErlDrvData e, char* buf, ErlDrvSizeT len) { int fd = (int)(long)e; - int ix = driver_data[fd].port_num; + ErlDrvPort ix = driver_data[fd].port_num; int pb = driver_data[fd].packet_bytes; int ofd = driver_data[fd].ofd; ssize_t n; @@ -2127,7 +2155,7 @@ static void output(ErlDrvData e, char* buf, ErlDrvSizeT len) return; /* 0; */ } -static int port_inp_failure(int port_num, int ready_fd, int res) +static int port_inp_failure(ErlDrvPort port_num, int ready_fd, int res) /* Result: 0 (eof) or -1 (error) */ { int err = errno; @@ -2177,7 +2205,7 @@ static int port_inp_failure(int port_num, int ready_fd, int res) static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd) { int fd = (int)(long)e; - int port_num; + ErlDrvPort port_num; int packet_bytes; int res; Uint h; @@ -2300,7 +2328,7 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd) static void ready_output(ErlDrvData e, ErlDrvEvent ready_fd) { int fd = (int)(long)e; - int ix = driver_data[fd].port_num; + ErlDrvPort ix = driver_data[fd].port_num; int n; struct iovec* iv; int vsize; @@ -2380,10 +2408,10 @@ void erts_do_break_handling(void) ** no interpretatione of this should be done by the rest of the ** emulator. The buffer should be at least 21 bytes long. */ -void sys_get_pid(char *buffer){ +void sys_get_pid(char *buffer, size_t buffer_size){ pid_t p = getpid(); /* Assume the pid is scalar and can rest in an unsigned long... */ - sprintf(buffer,"%lu",(unsigned long) p); + erts_snprintf(buffer, buffer_size, "%lu",(unsigned long) p); } int @@ -2609,19 +2637,20 @@ report_exit_status(ErtsSysReportExit *rep, int status) Port *pp; #ifdef ERTS_SMP CHLD_STAT_UNLOCK; -#endif + pp = erts_thr_id2port_sflgs(rep->port, + ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP); + CHLD_STAT_LOCK; +#else pp = erts_id2port_sflgs(rep->port, NULL, 0, ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP); -#ifdef ERTS_SMP - CHLD_STAT_LOCK; #endif if (pp) { if (rep->ifd >= 0) { driver_data[rep->ifd].alive = 0; driver_data[rep->ifd].status = status; - (void) driver_select((ErlDrvPort) internal_port_index(pp->id), + (void) driver_select((ErlDrvPort) pp, rep->ifd, (ERL_DRV_READ|ERL_DRV_USE), 1); @@ -2629,12 +2658,16 @@ report_exit_status(ErtsSysReportExit *rep, int status) if (rep->ofd >= 0) { driver_data[rep->ofd].alive = 0; driver_data[rep->ofd].status = status; - (void) driver_select((ErlDrvPort) internal_port_index(pp->id), + (void) driver_select((ErlDrvPort) pp, rep->ofd, (ERL_DRV_WRITE|ERL_DRV_USE), 1); } +#ifdef ERTS_SMP + erts_thr_port_release(pp); +#else erts_port_release(pp); +#endif } erts_free(ERTS_ALC_T_PRT_REP_EXIT, rep); } |