From c1241cd2ed230573bb81b52173d6cd2bd91176f2 Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 9 Jun 1999 09:21:37 +0000 Subject: thread bugs git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_3@482 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/extmk.rb.in | 31 ++++++--- ext/md5/md5init.c | 24 ++++++- ext/pty/pty.c | 4 ++ ext/readline/extconf.rb | 1 + ext/socket/addrinfo.h | 3 + ext/socket/depend | 4 +- ext/socket/extconf.rb | 9 ++- ext/socket/getnameinfo.c | 28 ++++---- ext/socket/socket.c | 46 +++++++++++-- ext/socket/sockport.h | 6 +- ext/tcltklib/tcltklib.c | 131 ++++++++++++++++++++++++------------- ext/tk/lib/tktext.rb | 165 ++++++++++++++++++++++++++++++++++++++++++++--- 12 files changed, 361 insertions(+), 91 deletions(-) (limited to 'ext') diff --git a/ext/extmk.rb.in b/ext/extmk.rb.in index c564b59b70..8090c2ab19 100644 --- a/ext/extmk.rb.in +++ b/ext/extmk.rb.in @@ -324,6 +324,19 @@ def create_makefile(target) $DLDFLAGS = $DLDFLAGS + " -L" + $topdir end + defflag = '' + if PLATFORM =~ /cygwin/ and not $static + if File.exist? target + ".def" + defflag = "--def=" + target + ".def" + end + if $libs + $libs = $libs + " @LIBRUBYARG@" + else + $libs = "@LIBRUBYARG@" + end + $DLDFLAGS = $DLDFLAGS + " -L" + $topdir + end + $srcdir = $top_srcdir + "/ext/" + $mdir mfile = open("Makefile", "w") mfile.printf "\ @@ -342,7 +355,7 @@ CC = @CC@ prefix = @prefix@ CFLAGS = %s -I#{$topdir} -I#{$top_srcdir} -I@includedir@ #{CFLAGS} #$CFLAGS %s DLDFLAGS = #$DLDFLAGS #$LDFLAGS -LDSHARED = @LDSHARED@ +LDSHARED = @LDSHARED@ #{defflag} ", if $static then "" else "@CCDLFLAGS@" end, $defs.join(" ") mfile.printf "\ @@ -367,7 +380,7 @@ archdir = $(pkglibdir)/@arch@ $objs = [] for f in Dir["#{$top_srcdir}/ext/#{$mdir}/*.{#{SRC_EXT.join(%q{,})}}"] f = File.basename(f) - f.sub!(/\.(c|cc)$/, ".o") + f.sub!(/(#{SRC_EXT.join(%q{|})})$/, "o") $objs.push f end end @@ -418,23 +431,21 @@ $(DLLIB): $(OBJS) $(DLLIB): $(OBJS) $(LDSHARED) $(DLDFLAGS) -o $(DLLIB) $(OBJS) $(LIBS) $(LOCAL_LIBS) " - elsif not SRC_EXT.detect{|ext| File.exist?(target + ext)} - if PLATFORM == "m68k-human" - mfile.printf "\ + elsif PLATFORM == "m68k-human" + mfile.printf "\ $(DLLIB): $(OBJS) ar cru $(DLLIB) $(OBJS) " - elsif PLATFORM =~ "-nextstep" || PLATFORM =~ "-openstep" || PLATFORM =~ "-rhapsody" - mfile.printf "\ + elsif PLATFORM =~ "-nextstep" || PLATFORM =~ "-openstep" || PLATFORM =~ "-rhapsody" + mfile.printf "\ $(DLLIB): $(OBJS) cc -r $(CFLAGS) -o $(DLLIB) $(OBJS) " - else - mfile.printf "\ + else + mfile.printf "\ $(DLLIB): $(OBJS) ld $(DLDFLAGS) -r -o $(DLLIB) $(OBJS) " - end end if File.exist?("depend") diff --git a/ext/md5/md5init.c b/ext/md5/md5init.c index e95e135812..e63258f3f1 100644 --- a/ext/md5/md5init.c +++ b/ext/md5/md5init.c @@ -29,8 +29,9 @@ md5_update(obj, str) Data_Get_Struct(obj, MD5_CTX, md5); MD5Update(md5, str->ptr, str->len); - return Qnil; + return obj; } + static VALUE md5_digest(obj) VALUE obj; @@ -45,6 +46,26 @@ md5_digest(obj) return rb_str_new(digest, 16); } +static VALUE +md5_hexdigest(obj) + VALUE obj; +{ + MD5_CTX *md5, ctx; + unsigned char digest[16]; + char buf[35]; + char *p = buf; + int i; + + Data_Get_Struct(obj, MD5_CTX, md5); + ctx = *md5; + MD5Final(digest, &ctx); + + for (i=0; i<16; i++) { + sprintf(buf+i*2, "%x", digest[i]); + } + return rb_str_new(buf, 32); +} + static VALUE md5_clone(obj) VALUE obj; @@ -90,5 +111,6 @@ Init_md5() rb_define_method(cMD5, "update", md5_update, 1); rb_define_method(cMD5, "digest", md5_digest, 0); + rb_define_method(cMD5, "hexdigest", md5_hexdigest, 0); rb_define_method(cMD5, "clone", md5_clone, 0); } diff --git a/ext/pty/pty.c b/ext/pty/pty.c index 0d3ba7f060..6462c3c7ca 100644 --- a/ext/pty/pty.c +++ b/ext/pty/pty.c @@ -19,6 +19,10 @@ #include #endif +#ifdef HAVE_UNISTD_H +#include +#endif + #define DEVICELEN 16 #if !defined(HAVE_OPENPTY) diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb index 0bd11bb946..f532f8a21d 100644 --- a/ext/readline/extconf.rb +++ b/ext/readline/extconf.rb @@ -16,6 +16,7 @@ if readline_dir $LDFLAGS = "-L#{readline_dir}" end +have_library("user32", nil) if /cygwin/ === PLATFORM have_library("termcap", "tgetnum") have_library("curses", "tgetnum") if have_header("readline/readline.h") and diff --git a/ext/socket/addrinfo.h b/ext/socket/addrinfo.h index 724f800c79..74fae207b9 100644 --- a/ext/socket/addrinfo.h +++ b/ext/socket/addrinfo.h @@ -27,6 +27,8 @@ * SUCH DAMAGE. */ +#ifndef ADDR_INFO_H +#define ADDR_INFO_H #ifndef HAVE_GETADDRINFO /* special compatibility hack */ @@ -167,3 +169,4 @@ Standard C system should have one. */ #endif #endif +#endif diff --git a/ext/socket/depend b/ext/socket/depend index 09e851498e..df2f0c5d16 100644 --- a/ext/socket/depend +++ b/ext/socket/depend @@ -1,3 +1,3 @@ socket.o : socket.c $(hdrdir)/ruby.h $(hdrdir)/config.h $(hdrdir)/defines.h $(hdrdir)/rubyio.h $(hdrdir)/rubysig.h sockport.h -getaddrinfo.o: getaddrinfo.c addrinfo.h sockport.h -getnameinfo.o: getnameinfo.c addrinfo.h sockport.h +getnameinfo.o: getnameinfo.c $(hdrdir)/config.h addrinfo.h sockport.h +getaddrinfo.o: getaddrinfo.c $(hdrdir)/config.h addrinfo.h sockport.h diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb index 37d8de5cbb..1e41c02261 100644 --- a/ext/socket/extconf.rb +++ b/ext/socket/extconf.rb @@ -6,8 +6,11 @@ case PLATFORM when /mswin32/ test_func = "WSACleanup" have_library("wsock32", "WSACleanup") -when /cygwin32/ +when /cygwin/ + $LDFLAGS << " -L/usr/lib" if File.directory?("/usr/lib") + $CFLAGS << " -I/usr/include" test_func = "socket" + have_library("bind", "gethostbyaddr") when /beos/ test_func = "socket" have_library("net", "socket") @@ -252,8 +255,8 @@ if have_getaddrinfo $CFLAGS="-DHAVE_GETADDRINFO "+$CFLAGS else $CFLAGS="-I. "+$CFLAGS - $objs += "getaddrinfo.o" - $objs += "getnameinfo.o" + $objs += ["getaddrinfo.o"] + $objs += ["getnameinfo.o"] have_func("inet_ntop") or have_func("inet_ntoa") have_func("inet_pton") or have_func("inet_aton") end diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c index f4da5bbf7a..5af329225c 100644 --- a/ext/socket/getnameinfo.c +++ b/ext/socket/getnameinfo.c @@ -61,6 +61,12 @@ #define YES 1 #define NO 0 +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + static struct afd { int a_af; int a_addrlen; @@ -68,18 +74,18 @@ static struct afd { int a_off; } afdl [] = { #ifdef INET6 - {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), - offsetof(struct sockaddr_in6, sin6_addr)}, +#define N_INET6 0 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#define N_INET 1 +#else +#define N_INET 0 #endif - {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), - offsetof(struct sockaddr_in, sin_addr)}, - {0, 0, 0}, -}; - -struct sockinet { - u_char si_len; - u_char si_family; - u_short si_port; + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0, 0}, }; #define ENI_NOSOCKET 0 diff --git a/ext/socket/socket.c b/ext/socket/socket.c index dda7eb06fc..0912ca9dd1 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -582,6 +582,21 @@ thread_write_select(fd) rb_thread_select(fd+1, 0, &fds, 0, 0); } +static int +ruby_socket(domain, type, proto) + int domain, type, proto; +{ + int fd; + + fd = socket(domain, type, proto); + if (fd < 0) { + if (errno == EMFILE || errno == ENFILE) { + rb_gc(); + fd = socket(domain, type, proto); + } + } +} + static int ruby_connect(fd, sockaddr, len, socks) int fd; @@ -683,11 +698,12 @@ open_inet(class, h, serv, type) fd = -1; for (res = res0; res; res = res->ai_next) { - status = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + status = ruby_socket(res->ai_family,res->ai_socktype,res->ai_protocol); syscall = "socket(2)"; fd = status; - if (fd < 0) + if (fd < 0) { continue; + } if (type == INET_SERVER) { status = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, @@ -939,8 +955,10 @@ open_unix(class, path, server) OpenFile *fptr; Check_SafeStr(path); - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) rb_sys_fail("socket(2)"); + fd = ruby_socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + rb_sys_fail("socket(2)"); + } MEMZERO(&sockaddr, struct sockaddr_un, 1); sockaddr.sun_family = AF_UNIX; @@ -1017,11 +1035,17 @@ udp_s_open(argc, argv, class) { VALUE arg; int socktype = AF_INET; + int fd; if (rb_scan_args(argc, argv, "01", &arg) == 1) { socktype = NUM2INT(arg); } - return sock_new(class, socket(socktype, SOCK_DGRAM, 0)); + fd = ruby_socket(socktype, SOCK_DGRAM, 0); + if (fd < 0) { + rb_sys_fail("socket(2) - udp"); + } + + return sock_new(class, fd); } static VALUE @@ -1312,7 +1336,7 @@ sock_s_open(class, domain, type, protocol) int d, t; setup_domain_and_type(domain, &d, type, &t); - fd = socket(d, t, NUM2INT(protocol)); + fd = ruby_socket(d, t, NUM2INT(protocol)); if (fd < 0) rb_sys_fail("socket(2)"); return sock_new(class, fd); @@ -1333,8 +1357,14 @@ sock_s_socketpair(class, domain, type, protocol) int d, t, sp[2]; setup_domain_and_type(domain, &d, type, &t); - if (socketpair(d, t, NUM2INT(protocol), sp) < 0) + again: + if (socketpair(d, t, NUM2INT(protocol), sp) < 0) { + if (errno == EMFILE || errno == ENFILE) { + rb_gc(); + goto again; + } rb_sys_fail("socketpair(2)"); + } return rb_assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1])); #else @@ -1920,6 +1950,8 @@ Init_socket() #endif #ifdef AF_INET6 sock_define_const("AF_INET6", AF_INET6); +#endif +#ifdef PF_INET6 sock_define_const("PF_INET6", PF_INET6); #endif diff --git a/ext/socket/sockport.h b/ext/socket/sockport.h index 3a2007362f..99bec91a1a 100644 --- a/ext/socket/sockport.h +++ b/ext/socket/sockport.h @@ -1,6 +1,6 @@ /************************************************ - sockcomm.h - + sockport.h - $Author$ $Date$ @@ -8,8 +8,8 @@ ************************************************/ -#ifndef SOCKCOMM_H -#define SOCKCOMM_H +#ifndef SOCKPORT_H +#define SOCKPORT_H #ifndef SA_LEN # ifdef HAVE_SA_LEN diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c index 5f6f9a0c02..6652b9409a 100644 --- a/ext/tcltklib/tcltklib.c +++ b/ext/tcltklib/tcltklib.c @@ -30,6 +30,8 @@ fprintf(stderr, ARG1, ARG2); fprintf(stderr, "\n"); } static VALUE eTkCallbackBreak; static VALUE eTkCallbackContinue; +static VALUE ip_invoke_real _((int, VALUE*, VALUE)); + /* from tkAppInit.c */ /* @@ -42,55 +44,47 @@ int *tclDummyMathPtr = (int *) matherr; /*---- module TclTkLib ----*/ -/* Tk_ThreadTimer */ -typedef struct { - Tcl_TimerToken token; - int flag; -} Tk_TimerData; - -/* timer callback */ -static void -_timer_for_tcl(clientData) - ClientData clientData; -{ - Tk_TimerData *timer = (Tk_TimerData*)clientData; +static VALUE main_thread; - timer->flag = 0; - CHECK_INTS; +struct invoke_queue { + int argc; + VALUE *argv; + VALUE obj; + int done; + VALUE result; + VALUE thread; + struct invoke_queue *next; +}; - if (timer->flag) { - Tk_DeleteTimerHandler(timer->token); - } - timer->token = Tk_CreateTimerHandler(200, _timer_for_tcl, - (ClientData)timer); - timer->flag = 1; -} +static struct invoke_queue *iqueue; /* execute Tk_MainLoop */ static VALUE lib_mainloop(self) VALUE self; { - Tk_TimerData *timer; - - timer = (Tk_TimerData *)ALLOC(Tk_TimerData); - timer->flag = 0; - timer->token = Tk_CreateTimerHandler(200, _timer_for_tcl, - (ClientData)timer); - timer->flag = 1; + struct invoke_queue *q, *tmp; + VALUE thread; DUMP1("start Tk_Mainloop"); while (Tk_GetNumMainWindows() > 0) { - Tcl_DoOneEvent(0); + Tcl_DoOneEvent(TCL_DONT_WAIT); CHECK_INTS; + q = iqueue; + while (q) { + tmp = q; + q = q->next; + if (!tmp->done) { + tmp->done = 1; + tmp->result = ip_invoke_real(tmp->argc, tmp->argv, tmp->obj); + thread = tmp->thread; + tmp = tmp->next; + rb_thread_run(thread); + } + } } DUMP1("stop Tk_Mainloop"); - if (timer->flag) { - Tk_DeleteTimerHandler(timer->token); - } - free(timer); - return Qnil; } @@ -206,11 +200,11 @@ ip_new(self) /* from Tcl_AppInit() */ DUMP1("Tcl_Init"); if (Tcl_Init(ptr->ip) == TCL_ERROR) { - rb_raise(rb_eRuntimeError, "Tcl_Init"); + rb_raise(rb_eRuntimeError, "%s", ptr->ip->result); } DUMP1("Tk_Init"); if (Tk_Init(ptr->ip) == TCL_ERROR) { - rb_raise(rb_eRuntimeError, "Tk_Init"); + rb_raise(rb_eRuntimeError, "%s", ptr->ip->result); } DUMP1("Tcl_StaticPackage(\"Tk\")"); Tcl_StaticPackage(ptr->ip, "Tk", Tk_Init, @@ -324,14 +318,13 @@ ip_fromUTF8(self, str, encodename) static VALUE -ip_invoke(argc, argv, obj) +ip_invoke_real(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { struct tcltkip *ptr; /* tcltkip data struct */ int i; - int object = 0; Tcl_CmdInfo info; char *cmd; char **av = (char **)NULL; @@ -350,13 +343,10 @@ ip_invoke(argc, argv, obj) if (!Tcl_GetCommandInfo(ptr->ip, cmd, &info)) { rb_raise(rb_eNameError, "invalid command name `%s'", cmd); } -#if TCL_MAJOR_VERSION >= 8 - object = info.isNativeObjectProc; -#endif /* memory allocation for arguments of this command */ - if (object) { #if TCL_MAJOR_VERSION >= 8 + if (info.isNativeObjectProc) { /* object interface */ ov = (Tcl_Obj **)ALLOCA_N(Tcl_Obj *, argc+1); for (i = 0; i < argc; ++i) { @@ -365,8 +355,10 @@ ip_invoke(argc, argv, obj) Tcl_IncrRefCount(ov[i]); } ov[argc] = (Tcl_Obj *)NULL; + } + else #endif - } else { + { /* string interface */ av = (char **)ALLOCA_N(char *, argc+1); for (i = 0; i < argc; ++i) { @@ -381,8 +373,8 @@ ip_invoke(argc, argv, obj) Tcl_ResetResult(ptr->ip); /* Invoke the C procedure */ - if (object) { #if TCL_MAJOR_VERSION >= 8 + if (info.isNativeObjectProc) { int dummy; ptr->return_value = (*info.objProc)(info.objClientData, ptr->ip, argc, ov); @@ -395,9 +387,10 @@ ip_invoke(argc, argv, obj) for (i=0; ireturn_value = (*info.proc)(info.clientData, ptr->ip, argc, av); } @@ -410,6 +403,51 @@ ip_invoke(argc, argv, obj) return rb_str_new2(ptr->ip->result); } +static VALUE +ip_invoke(argc, argv, obj) + int argc; + VALUE *argv; + VALUE obj; +{ + struct invoke_queue *tmp, *p; + VALUE result = rb_thread_current(); + + if (result == main_thread) { + return ip_invoke_real(argc, argv, obj); + } + tmp = ALLOC(struct invoke_queue); + tmp->obj = obj; + tmp->argc = argc; + tmp->argv = ALLOC_N(VALUE, argc); + MEMCPY(tmp->argv, argv, VALUE, argc); + tmp->thread = result; + tmp->done = 0; + + tmp->next = iqueue; + iqueue = tmp; + + rb_thread_stop(); + result = tmp->result; + if (iqueue == tmp) { + iqueue = tmp->next; + free(tmp->argv); + free(tmp); + return result; + } + + p = iqueue; + while (p->next) { + if (p->next == tmp) { + p->next = tmp->next; + free(tmp->argv); + free(tmp); + break; + } + p = p->next; + } + return result; +} + /* get return code from Tcl_Eval() */ static VALUE ip_retval(self) @@ -454,6 +492,7 @@ Init_tcltklib() rb_define_method(ip, "_return_value", ip_retval, 0); rb_define_method(ip, "mainloop", lib_mainloop, 0); + main_thread = rb_thread_current(); #ifdef __MACOS__ _macinit(); #endif diff --git a/ext/tk/lib/tktext.rb b/ext/tk/lib/tktext.rb index 3dde30d60d..3d8e4fa405 100644 --- a/ext/tk/lib/tktext.rb +++ b/ext/tk/lib/tktext.rb @@ -285,8 +285,8 @@ class TkTextval}) else tk_send 'tag', 'configure', tag, "-#{key}", val @@ -320,7 +320,7 @@ class TkText