From: Park Heesob Date: 2003-12-24T11:50:14+09:00 Subject: Re: bug: threads and win32 Hi, From: "anon luker" > > > > > > >Is this a common problem? Are there good workarounds? I thought Ruby > > >implemented the threads in some internal system independant way, so > > >this is confusing to me. Any help/info would be greatly appreciated. > > > > I may be wrong but there is no workaround for this. Ruby Threads do > > block on IO within windows. > > IIRC that should be because ruby transparently uses select() to hnadle > > IO, but select() on windows only works with sockets, and thus any > > other IO blocks the whole interpreter. > Yuck! On a hunch, I tried the cygwin version. It works, but _very_ > slowly. Far too slow for socket programming. I must be missing > something, since the official tagline for Ruby includes "Ruby features > OS independent threading. Thus, for all platforms on which Ruby runs, > you also have multithreading, regardless of if the OS supports it or > not, even on MS-DOS! ;-)" What I want to do seems pretty basic, > though, so if Ruby supports threads and can't meet my needs, then > something is wrong. > > > Feel free to hack ruby and fix > > this :) > I'll just use java or something for this project. Maybe I'll be lucky > enough to get paid to hack on ruby one day... until then, I'm > constrained to using _working_ solutions. > > My followup question is: How does one do asynch io (ala sockets) in > Ruby under Windows? Threads seemed like the most natural way, but > nonblocking IO may work, too. Unfortunately, the langauge reference > that I have doesn't really document all of the SO_* flags that the > recv line of socket methods support and a quick look at the constants > doesn't show anything obvious like SO_NOBLOCK. Any advice would be > appreciated. > > thanks > > Try this patch to win32/win32.c ( ruby 1.8.0 ) I adoted this from php 5.0.0 beta 3 source code. I belive it will fix thread and blocking IO problem whinin Windows. =================================================================== @@ -1775,6 +1775,13 @@ rb_w32_select (int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *timeout) { + DWORD ms_total, limit; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS]; + int n_handles = 0, i; + fd_set aread, awrite, aexcept; + int retcode; + long r; fd_set file_rd; fd_set file_wr; @@ -1783,6 +1790,28 @@ #endif /* USE_INTERRUPT_WINSOCK */ int file_nfds; +#define SAFE_FD_ISSET(fd, set) (set != NULL && rb_w32_fdisset(fd, set)) + + /* calculate how long we need to wait in milliseconds */ + if (timeout == NULL) { + ms_total = INFINITE; + } else { + ms_total = timeout->tv_sec * 1000; + ms_total += timeout->tv_usec / 1000; + } + + /* build an array of handles for non-sockets */ + for (i = 0; i < nfds; i++) { + if (SAFE_FD_ISSET(i, rd) || SAFE_FD_ISSET(i, wr) || SAFE_FD_ISSET(i, ex)) { + handles[n_handles] = (HANDLE)_get_osfhandle(i); + if ((DWORD)handles[n_handles] != 0xffffffff) { + handle_slot_to_fd[n_handles] = i; + n_handles++; + } + } + } + + if (!NtSocketsInitialized) { StartSockets(); } @@ -1799,10 +1828,49 @@ file_nfds += extract_file_fd(wr, &file_wr); if (file_nfds) { - // assume normal files are always readable/writable - // fake read/write fd_set and return value - if (rd) *rd = file_rd; - if (wr) *wr = file_wr; + FD_ZERO(&aread); + FD_ZERO(&awrite); + FD_ZERO(&aexcept); + + limit = GetTickCount() + ms_total; + do { + DWORD wret; + retcode = 0; + + wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE, retcode > 0 ? 0 : 100, QS_ALLEVENTS); + + if (wret == WAIT_TIMEOUT) { + /* set retcode to 0; this is the default. + * select() may have set it to something else, + * in which case we leave it alone, so this branch + * does nothing */ + ; + } else if (wret == WAIT_FAILED) { + if (retcode == 0) { + retcode = -1; + } + } else { + if (retcode < 0) { + retcode = 0; + } + for (i = 0; i < n_handles; i++) { + if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) { + if (SAFE_FD_ISSET(handle_slot_to_fd[i], rd)) { + rb_w32_fdset(handle_slot_to_fd[i], &aread); + } + if (SAFE_FD_ISSET(handle_slot_to_fd[i], wr)) { + rb_w32_fdset(handle_slot_to_fd[i], &awrite); + } + if (SAFE_FD_ISSET(handle_slot_to_fd[i], ex)) { + rb_w32_fdset(handle_slot_to_fd[i], &aexcept); + } + retcode++; + } + } + } + } while (retcode == 0 && (ms_total == INFINITE || GetTickCount() < limit)); + if (rd) *rd = aread; + if (wr) *wr = awrite; return file_nfds; } =============================================================== Regards, Park Heesob