diff --git a/ChangeLog b/ChangeLog index d81ef4c335..6ab050bc2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,13 +1,38 @@ +Fri Mar 7 03:31:36 2003 Yukihiro Matsumoto + + * parse.y (dsym): :"symbol string" style should not contain `\0'. + + * process.c (proc_detach): new method Proc#detach(pid) which + create background watcher thread to issue waitpid. [new] + + * process.c (rb_detach_process): utility function to detach + process from C code. + + * ext/pty/pty.c (pty_finalize_syswait): terminate watcher thread, + and detach child process (by creating new idle waitpid watcher + thread). + + * ext/pty/pty.c (pty_syswait): may lost signal stopped child. + Fri Mar 7 00:30:33 2003 WATANABE Hirofumi * ext/Win32API/Win32API.c: no longer use inline-asms. * ext/Win32API/extconf.rb: no need to add gcc options. +Thu Mar 6 13:02:10 2003 Yukihiro Matsumoto + + * parse.y (reswords): fix reswords list. + Wed Mar 5 12:13:21 2003 WATANABE Hirofumi * configure.in: better YACC support on HP-UX. +Wed Mar 5 05:55:20 2003 Yukihiro Matsumoto + + * string.c (rb_str_cat): remove ptr NULL check and MEMZERO(). ptr + must be non NULL. + Tue Mar 04 23:12:07 2003 Nobuyoshi Nakada * configure.in, bcc32/Makefile.sub, win32/Makefile.sub: define @@ -21,10 +46,10 @@ Tue Mar 04 23:12:07 2003 Nobuyoshi Nakada Tue Mar 4 17:54:30 2003 Yukihiro Matsumoto - * array.c (rb_ary_aref): give warning if index is a symbol. + * array.c (rb_ary_aref): raise TypeError if index is a symbol. [ruby-list:37217] - * array.c (rb_ary_aset): raise TypeError if index is a symbol. + * array.c (rb_ary_aset): ditto. Tue Nov 13 14:39:11 2001 WATANABE Tetsuya diff --git a/eval.c b/eval.c index 17f7f774f3..7dbc4d7ab8 100644 --- a/eval.c +++ b/eval.c @@ -4024,17 +4024,19 @@ massign(self, node, val, pcall) int pcall; { NODE *list; + VALUE tmp; long i = 0, len; len = RARRAY(val)->len; list = node->nd_head; - if (len == 1 && list) { + if (len == 1 && list && (list->nd_next || node->nd_args)) { VALUE v = RARRAY(val)->ptr[0]; - VALUE tmp = rb_check_array_type(v); + tmp = rb_check_array_type(v); if (NIL_P(tmp)) { assign(self, list->nd_head, v, pcall); list = list->nd_next; + i = 1; } else { len = RARRAY(tmp)->len; @@ -4043,13 +4045,13 @@ massign(self, node, val, pcall) list = list->nd_next; } } - i = 1; } else { for (; list && ind_head, RARRAY(val)->ptr[i], pcall); list = list->nd_next; } + tmp = val; } if (pcall && list) goto arg_error; if (node->nd_args) { @@ -4057,7 +4059,7 @@ massign(self, node, val, pcall) /* no check for mere `*' */ } else if (!list && ind_args, rb_ary_new4(len-i, RARRAY(val)->ptr+i), pcall); + assign(self, node->nd_args, rb_ary_new4(len-i, RARRAY(tmp)->ptr+i), pcall); } else { assign(self, node->nd_args, rb_ary_new2(0), pcall); @@ -8640,7 +8642,7 @@ rb_thread_run(thread) return thread; } -static VALUE +VALUE rb_thread_kill(thread) VALUE thread; { diff --git a/ext/pty/README b/ext/pty/README index a09469d39c..42c7d4f891 100644 --- a/ext/pty/README +++ b/ext/pty/README @@ -33,43 +33,15 @@ following module fungtions: the array is passed to the block as block parameters, and the function itself returns nil. - While the process spawned by this function is active, SIGCHLD - is captured to handle the change of the child process. When the - child process is suspended or finished, an exception is raised. - As all SIGCHLD signal is captured and processed by PTY module, - you can't use other function or method which spawns subprosesses - (including signal() and IO.popen()) while the PTY subprocesses - are active. Otherwise, unexpected exception will occur. To avoid - this problem, see protect_signal() below. - - If this function is called with an iterator block, SIGCHLD signal - is captured only within the block. Therefore, it is risky to use - File objects for PTY subprocess outside the iterator block. - + When the child process is suspended or finished, an exception is + raised. If this function is called with an iterator block, + exception is raised only within the block. Child process + monitor is terminated on block exit. protect_signal + reset_signal - This function takes an iterator block. Within the iterator block, - no exception is raised even if any subprocess is terminated. - This function is used to enable functions like system() or IO.popen() - while PTY subprocess is active. For example, - - PTY.spawn("command_foo") do |r,w| - ... - ... - PTY.protect_signal do - system "some other commands" - end - ... - end - - disables to send exception when "some other commands" is - terminated. - - reset_signal - - Disables to handle SIGCHLD while PTY subprocess is active. - + These functions are obsolete in this version of pty. 4. License diff --git a/ext/pty/pty.c b/ext/pty/pty.c index b7c69fe400..f1d4f73a18 100644 --- a/ext/pty/pty.c +++ b/ext/pty/pty.c @@ -133,44 +133,50 @@ struct pty_info { VALUE thread; }; +static void +raise_from_wait(state, info) + struct pty_info *info; + char *state; +{ + extern VALUE rb_last_status; + char buf[1024]; + VALUE exc; + + snprintf(buf, sizeof(buf), "pty - %s: %d", state, info->child_pid); + exc = rb_exc_new2(eChildExited, buf); + rb_iv_set(exc, "status", rb_last_status); + rb_funcall(info->thread, rb_intern("raise"), 1, exc); +} + static VALUE pty_syswait(info) struct pty_info *info; { - extern VALUE rb_last_status; int cpid, status; - char buf[1024]; - VALUE exc, st; - char *state = "changed"; - cpid = rb_waitpid(info->child_pid, &status, WUNTRACED); - st = rb_last_status; - - if (cpid == 0 || cpid == -1) - return Qnil; + for (;;) { + cpid = rb_waitpid(info->child_pid, &status, WUNTRACED); + if (cpid == -1) return Qnil; -#ifdef IF_STOPPED - if (IF_STOPPED(status)) { /* suspend */ - state = "stopped"; - } -#else -#ifdef WIFSTOPPED - if (WIFSTOPPED(status)) { /* suspend */ - state = "stopped"; - } +#if defined(IF_STOPPED) + if (IF_STOPPED(status)) { /* suspend */ + raise_from_wait("stopped", info); + } +#elif defined(WIFSTOPPED) + if (WIFSTOPPED(status)) { /* suspend */ + raise_from_wait("stopped", info); + } #else ---->> Either IF_STOPPED or WIFSTOPPED is needed <<---- -#endif /* WIFSTOPPED */ -#endif /* IF_STOPPED */ - if (WIFEXITED(status)) { - state = "exit"; +#endif /* WIFSTOPPED | IF_STOPPED */ + else if (kill(info->child_pid, 0) == 0) { + raise_from_wait("changed", info); + } + else { + raise_from_wait("exited", info); + return Qnil; + } } - - snprintf(buf, sizeof(buf), "pty - %s: %d", state, cpid); - exc = rb_exc_new2(eChildExited, buf); - rb_iv_set(exc, "status", st); - rb_funcall(info->thread, rb_intern("raise"), 1, exc); - return Qnil; } static void getDevice _((int*, int*)); @@ -290,27 +296,14 @@ establishShell(argc, argv, info) } static VALUE -pty_kill_child(info) +pty_finalize_syswait(info) struct pty_info *info; { - if (rb_funcall(info->thread, rb_intern("alive?"), 0, 0) == Qtrue && - kill(info->child_pid, 0) == 0) { - rb_thread_schedule(); - if (kill(info->child_pid, SIGTERM) == 0) { - rb_thread_schedule(); - if (kill(info->child_pid, 0) == 0) { - kill(info->child_pid, SIGINT); - rb_thread_schedule(); - if (kill(info->child_pid, 0) == 0) - kill(info->child_pid, SIGKILL); - } - } - } - rb_funcall(info->thread, rb_intern("join"), 0, 0); + rb_thread_kill(info->thread); + rb_detach_process(info->child_pid); return Qnil; } - #ifdef HAVE_OPENPTY /* * Use openpty(3) of 4.3BSD Reno and later, @@ -447,7 +440,7 @@ pty_getpty(argc, argv, self) thinfo.child_pid = info.child_pid; if (rb_block_given_p()) { - rb_ensure(rb_yield, res, pty_kill_child, (VALUE)&thinfo); + rb_ensure(rb_yield, res, pty_finalize_syswait, (VALUE)&thinfo); return Qnil; } return res; diff --git a/ext/pty/script.rb b/ext/pty/script.rb index 3084935637..dbb933171f 100644 --- a/ext/pty/script.rb +++ b/ext/pty/script.rb @@ -10,8 +10,7 @@ logfile = File.open(ofile,"a") system "stty -echo raw lnext ^_" -PTY.spawn("/bin/csh") do - |r_pty,w_pty,pid| +PTY.spawn("/bin/csh") do |r_pty,w_pty,pid| Thread.new do while true diff --git a/intern.h b/intern.h index a53a9a92d4..e1872938b8 100644 --- a/intern.h +++ b/intern.h @@ -199,6 +199,7 @@ void rb_thread_sleep_forever _((void)); VALUE rb_thread_stop _((void)); VALUE rb_thread_wakeup _((VALUE)); VALUE rb_thread_run _((VALUE)); +VALUE rb_thread_kill _((VALUE)); VALUE rb_thread_create _((VALUE (*)(ANYARGS), void*)); void rb_thread_interrupt _((void)); void rb_thread_trap_eval _((VALUE, int)); diff --git a/parse.y b/parse.y index c1e75b3fb1..1ee5633042 100644 --- a/parse.y +++ b/parse.y @@ -924,9 +924,10 @@ op : '|' { $$ = '|'; } reswords : k__LINE__ | k__FILE__ | klBEGIN | klEND | kALIAS | kAND | kBEGIN | kBREAK | kCASE | kCLASS | kDEF | kDEFINED | kDO | kELSE | kELSIF | kEND | kENSURE | kFALSE - | kFOR | kIF_MOD | kIN | kMODULE | kNEXT | kNIL | kNOT + | kFOR | kIN | kMODULE | kNEXT | kNIL | kNOT | kOR | kREDO | kRESCUE | kRETRY | kRETURN | kSELF | kSUPER | kTHEN | kTRUE | kUNDEF | kWHEN | kYIELD + | kIF_MOD | kUNLESS_MOD | kWHILE_MOD | kUNTIL_MOD | kRESCUE_MOD ; arg : lhs '=' arg @@ -2095,13 +2096,16 @@ dsym : tSYMBEG xstring_contents tSTRING_END } else { switch (nd_type($$)) { - case NODE_STR: - $$->nd_lit = ID2SYM(rb_intern(RSTRING($$->nd_lit)->ptr)); - nd_set_type($$, NODE_LIT); - break; case NODE_DSTR: nd_set_type($$, NODE_DSYM); break; + case NODE_STR: + if (strlen(RSTRING($$->nd_lit)->ptr) == RSTRING($$->nd_lit)->len) { + $$->nd_lit = ID2SYM(rb_intern(RSTRING($$->nd_lit)->ptr)); + nd_set_type($$, NODE_LIT); + break; + } + /* fall through */ default: $$ = rb_node_newnode(NODE_DSYM, rb_str_new(0, 0), 1, NEW_LIST($$)); diff --git a/process.c b/process.c index 38cdfb0964..3fc7f9e065 100644 --- a/process.c +++ b/process.c @@ -411,6 +411,33 @@ proc_waitall() return result; } +static VALUE +detach_process_watcer(pid_p) + int *pid_p; +{ + int cpid, status; + + for (;;) { + cpid = rb_waitpid(*pid_p, &status, WNOHANG); + if (cpid == -1) return Qnil; + rb_thread_sleep(1); + } +} + +void +rb_detach_process(pid) + int pid; +{ + rb_thread_create(detach_process_watcer, (void*)&pid); +} + +static VALUE +proc_detach(obj, pid) + VALUE pid; +{ + rb_detach_process(NUM2INT(pid)); +} + #ifndef HAVE_STRING_H char *strtok(); #endif @@ -1319,6 +1346,7 @@ Init_process() rb_define_module_function(rb_mProcess, "waitpid", proc_wait, -1); rb_define_module_function(rb_mProcess, "waitpid2", proc_wait2, -1); rb_define_module_function(rb_mProcess, "waitall", proc_waitall, 0); + rb_define_module_function(rb_mProcess, "detach", proc_detach, 1); rb_cProcStatus = rb_define_class_under(rb_mProcess, "Status", rb_cObject); rb_undef_method(CLASS_OF(rb_cProcStatus), "new"); diff --git a/string.c b/string.c index e4308be0f5..a273400d89 100644 --- a/string.c +++ b/string.c @@ -614,12 +614,7 @@ rb_str_cat(str, ptr, len) if (FL_TEST(str, STR_ASSOC)) { rb_str_modify(str); REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len); - if (ptr) { - memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); - } - else { - MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, len); - } + memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); RSTRING(str)->len += len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ return str; @@ -3076,7 +3071,7 @@ rb_str_intern(str) rb_raise(rb_eArgError, "interning empty string"); } if (strlen(RSTRING(str)->ptr) != RSTRING(str)->len) - rb_raise(rb_eArgError, "string contains `\\0'"); + rb_raise(rb_eArgError, "symbol string may not contain `\\0'"); id = rb_intern(RSTRING(str)->ptr); return ID2SYM(id); }