* 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.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3561 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2003-03-07 05:59:42 +00:00
Родитель 5208fec1cf
Коммит 9d77639f30
9 изменённых файлов: 119 добавлений и 100 удалений

Просмотреть файл

@ -1,13 +1,38 @@
Fri Mar 7 03:31:36 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
* 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 <eban@ruby-lang.org>
* 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 <matz@ruby-lang.org>
* parse.y (reswords): fix reswords list.
Wed Mar 5 12:13:21 2003 WATANABE Hirofumi <eban@ruby-lang.org>
* configure.in: better YACC support on HP-UX.
Wed Mar 5 05:55:20 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
* 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 <nobu.nokada@softhome.net>
* configure.in, bcc32/Makefile.sub, win32/Makefile.sub: define
@ -21,10 +46,10 @@ Tue Mar 04 23:12:07 2003 Nobuyoshi Nakada <nobu.nokada@softhome.net>
Tue Mar 4 17:54:30 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
* 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 <tetsu@jpn.hp.com>

12
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 && i<len; i++) {
assign(self, list->nd_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 && i<len) {
assign(self, node->nd_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;
{

Просмотреть файл

@ -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
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

Просмотреть файл

@ -133,45 +133,51 @@ 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";
for (;;) {
cpid = rb_waitpid(info->child_pid, &status, WUNTRACED);
st = rb_last_status;
if (cpid == -1) return Qnil;
if (cpid == 0 || cpid == -1)
return Qnil;
#ifdef IF_STOPPED
#if defined(IF_STOPPED)
if (IF_STOPPED(status)) { /* suspend */
state = "stopped";
raise_from_wait("stopped", info);
}
#else
#ifdef WIFSTOPPED
#elif defined(WIFSTOPPED)
if (WIFSTOPPED(status)) { /* suspend */
state = "stopped";
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);
}
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);
else {
raise_from_wait("exited", info);
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;

Просмотреть файл

@ -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

Просмотреть файл

@ -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));

14
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($$));

Просмотреть файл

@ -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");

Просмотреть файл

@ -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);
}
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);
}