* daemon-messages.c: Retry if the communication with the daemon is
authorLluis Sanchez <lluis@novell.com>
Thu, 20 May 2004 20:09:58 +0000 (20:09 -0000)
committerLluis Sanchez <lluis@novell.com>
Thu, 20 May 2004 20:09:58 +0000 (20:09 -0000)
  interrupted by a signal.
* io.c, sockets.c: Check for EINTR in every syscall that can be interrumped.
  Only return an error in this case if there is something in the apc queue
  (which means that it is an interruption requested by the "user").
* processes.c: Use WaitForSingleObjectEx. No need to pass "alertable" as
  true since the wait is small.
* shared.c: Retry write calls when interrumped by a signal.
* timed-thread.h, timed-thread.c: added _wapi_thread_apc_pending, which
  returns TRUE if there are pending asynchronous calls (APC) for the
  provided thread. Also added _wapi_thread_dispatch_apc_queue which calls
  the enqueued APCs. Defined a new struct ApcInfo that holds information
  about an enqueued APC.
* thread-private.h, threads.c: Implemented QueueUserAPC (which does the same
  as in win32),_wapi_thread_apc_pending and _wapi_thread_dispatch_apc_queue.
  These last two methods call the corresponding apc methods in
  thread-private using the provided thread handle.
* threads.h: Added QueueUserAPC.
* uglify.h: Added WapiApcProc (needed by QueueUserAPC).
* wait.c, wait.h: Changed WaitForSingleObject to WaitForSingleObjectEx, and
  WaitForMultipleObjects to WaitForMultipleObjectsEx. Implemented support
  for APCs in those two methods and also in SleepEx.

svn path=/trunk/mono/; revision=27777

14 files changed:
mono/io-layer/ChangeLog
mono/io-layer/daemon-messages.c
mono/io-layer/io.c
mono/io-layer/processes.c
mono/io-layer/shared.c
mono/io-layer/sockets.c
mono/io-layer/thread-private.h
mono/io-layer/threads.c
mono/io-layer/threads.h
mono/io-layer/timed-thread.c
mono/io-layer/timed-thread.h
mono/io-layer/uglify.h
mono/io-layer/wait.c
mono/io-layer/wait.h

index 413014e631fcc84f968ee3871a9327e8bd609c6c..2b87f5f4a93f1337f44dafb0794302a5a104b61a 100644 (file)
@@ -1,3 +1,28 @@
+2004-05-20  Lluis Sanchez Gual  <lluis@ximian.com>
+
+       * daemon-messages.c: Retry if the communication with the daemon is
+         interrupted by a signal.
+       * io.c, sockets.c: Check for EINTR in every syscall that can be interrumped. 
+         Only return an error in this case if there is something in the apc queue
+         (which means that it is an interruption requested by the "user").
+       * processes.c: Use WaitForSingleObjectEx. No need to pass "alertable" as
+         true since the wait is small.
+       * shared.c: Retry write calls when interrumped by a signal.
+       * timed-thread.h, timed-thread.c: added _wapi_thread_apc_pending, which
+         returns TRUE if there are pending asynchronous calls (APC) for the
+         provided thread. Also added _wapi_thread_dispatch_apc_queue which calls
+         the enqueued APCs. Defined a new struct ApcInfo that holds information
+         about an enqueued APC.
+       * thread-private.h, threads.c: Implemented QueueUserAPC (which does the same
+         as in win32),_wapi_thread_apc_pending and _wapi_thread_dispatch_apc_queue. 
+         These last two methods call the corresponding apc methods in 
+         thread-private using the provided thread handle.
+       * threads.h: Added QueueUserAPC.
+       * uglify.h: Added WapiApcProc (needed by QueueUserAPC).
+       * wait.c, wait.h: Changed WaitForSingleObject to WaitForSingleObjectEx, and
+         WaitForMultipleObjects to WaitForMultipleObjectsEx. Implemented support
+         for APCs in those two methods and also in SleepEx.
+
 2004-05-17  Dick Porter  <dick@ximian.com>
 
        * io.c (CopyFile): Speed up.  Fixes bug 57859.
index 2419b1f50d5d7f196f71a05e8db6a8eecc50089d..c7c929cd348b4341b8be8c56d40730a3e237e875 100644 (file)
@@ -75,11 +75,18 @@ static void _wapi_daemon_request_response_internal (int fd,
        g_assert (ret == 0);
        
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=sendmsg (fd, msg, MSG_NOSIGNAL);
+       do {
+               ret=sendmsg (fd, msg, MSG_NOSIGNAL);
+       }
+       while (ret==-1 && errno==EINTR);
 #else
        old_sigpipe = signal (SIGPIPE, SIG_IGN);
-       ret=sendmsg (fd, msg, 0);
+       do {
+               ret=sendmsg (fd, msg, 0);
+       }
+       while (ret==-1 && errno==EINTR);
 #endif
+
        if(ret!=sizeof(WapiHandleRequest)) {
                if(errno==EPIPE) {
                        g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
@@ -92,11 +99,18 @@ static void _wapi_daemon_request_response_internal (int fd,
        }
 
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
+       do {
+               ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
+       }
+       while (ret==-1 && errno==EINTR);
 #else
-       ret=recv (fd, resp, sizeof(WapiHandleResponse), 0);
+       do {
+               ret=recv (fd, resp, sizeof(WapiHandleResponse), 0);
+       }
+       while (ret==-1 && errno==EINTR);
        signal (SIGPIPE, old_sigpipe);
 #endif
+
        if(ret==-1) {
                if(errno==EPIPE) {
                        g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
@@ -107,7 +121,7 @@ static void _wapi_daemon_request_response_internal (int fd,
                        g_assert_not_reached ();
                }
        }
-
+               
        ret = mono_mutex_unlock (&req_mutex);
        g_assert (ret == 0);
        
@@ -195,11 +209,15 @@ int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds,
        iov.iov_base=req;
        iov.iov_len=sizeof(WapiHandleRequest);
        
+       do {
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=recvmsg (fd, &msg, MSG_NOSIGNAL);
+               ret=recvmsg (fd, &msg, MSG_NOSIGNAL);
 #else
-       ret=recvmsg (fd, &msg, 0);
+               ret=recvmsg (fd, &msg, 0);
 #endif
+       }
+       while (ret==-1 && errno==EINTR);
+
        if(ret==-1 || ret!= sizeof(WapiHandleRequest)) {
                /* Make sure we dont do anything with this response */
                req->type=WapiHandleRequestType_Error;
@@ -255,13 +273,18 @@ int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds,
 int _wapi_daemon_response (int fd, WapiHandleResponse *resp)
 {
        int ret;
-       
+
+       do {
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
+               ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
 #else
-       ret=send (fd, resp, sizeof(WapiHandleResponse), 0);
+               ret=send (fd, resp, sizeof(WapiHandleResponse), 0);
 #endif
+       }
+       while (ret==-1 && errno==EINTR);
+
 #ifdef DEBUG
+
        if(ret==-1 || ret != sizeof(WapiHandleResponse)) {
                g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
                           strerror (errno));
index e10a8250af18eba5c42a57abcbefe3efdbc0e223..f4f93f1fd09060a326f50c0c8d7df41695251483 100644 (file)
@@ -339,7 +339,11 @@ static gboolean file_read(gpointer handle, gpointer buffer,
        }
 
        if (file_private_handle->async == FALSE) {
-               ret=read(file_private_handle->fd, buffer, numbytes);
+               do {
+                       ret=read(file_private_handle->fd, buffer, numbytes);
+               }
+               while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+                       
                if(ret==-1) {
                        gint err = errno;
 
@@ -450,7 +454,11 @@ static gboolean file_write(gpointer handle, gconstpointer buffer,
        }
        
        if (file_private_handle->async == FALSE) {
-               ret=write(file_private_handle->fd, buffer, numbytes);
+               do {
+                       ret=write(file_private_handle->fd, buffer, numbytes);
+               }
+               while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
                if(ret==-1) {
 #ifdef DEBUG
                        g_message(G_GNUC_PRETTY_FUNCTION
@@ -743,7 +751,11 @@ static gboolean file_setendoffile(gpointer handle)
        
        if(pos>size) {
                /* extend */
-               ret=write(file_private_handle->fd, "", 1);
+               do {
+                       ret=write(file_private_handle->fd, "", 1);
+               }
+               while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
                if(ret==-1) {
 #ifdef DEBUG
                        g_message(G_GNUC_PRETTY_FUNCTION
@@ -759,7 +771,11 @@ static gboolean file_setendoffile(gpointer handle)
        /* always truncate, because the extend write() adds an extra
         * byte to the end of the file
         */
-       ret=ftruncate(file_private_handle->fd, pos);
+       do {
+               ret=ftruncate(file_private_handle->fd, pos);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+                       
        if(ret==-1) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION
@@ -1103,7 +1119,11 @@ static gboolean console_read(gpointer handle, gpointer buffer,
                return(FALSE);
        }
        
-       ret=read(console_private_handle->fd, buffer, numbytes);
+       do {
+               ret=read(console_private_handle->fd, buffer, numbytes);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(ret==-1) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION
@@ -1152,7 +1172,11 @@ static gboolean console_write(gpointer handle, gconstpointer buffer,
                return(FALSE);
        }
        
-       ret=write(console_private_handle->fd, buffer, numbytes);
+       do {
+               ret=write(console_private_handle->fd, buffer, numbytes);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(ret==-1) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION
@@ -1260,7 +1284,11 @@ static gboolean pipe_read (gpointer handle, gpointer buffer,
                   handle, pipe_private_handle->fd);
 #endif
 
-       ret=read(pipe_private_handle->fd, buffer, numbytes);
+       do {
+               ret=read(pipe_private_handle->fd, buffer, numbytes);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+               
        if(ret==-1) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION
@@ -1318,8 +1346,12 @@ static gboolean pipe_write(gpointer handle, gconstpointer buffer,
                   ": writing up to %d bytes to pipe %p (fd %d)", numbytes,
                   handle, pipe_private_handle->fd);
 #endif
-       
-       ret=write(pipe_private_handle->fd, buffer, numbytes);
+
+       do {
+               ret=write(pipe_private_handle->fd, buffer, numbytes);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(ret==-1) {
 #ifdef DEBUG
                g_message(G_GNUC_PRETTY_FUNCTION
@@ -1768,8 +1800,9 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
        
        for (;;) {
                remain = read (src_fd, buf, buf_size);
+               
                if (remain < 0) {
-                       if (errno == EINTR) {
+                       if (errno == EINTR && !_wapi_thread_cur_apc_pending()) {
                                continue;
                        }
                        
@@ -1789,6 +1822,9 @@ gboolean CopyFile (const gunichar2 *name, const gunichar2 *dest_name,
 
                while (remain > 0) {
                        if ((n = write (dest_fd, buf, remain)) < 0) {
+                               if (errno == EINTR && !_wapi_thread_cur_apc_pending())
+                                       continue;
+
                                _wapi_set_last_error_from_errno ();
 #ifdef DEBUG
                                g_message (G_GNUC_PRETTY_FUNCTION ": write failed.");
@@ -1834,7 +1870,11 @@ static gpointer stdhandle_create (int fd, const guchar *name)
 #endif
        
        /* Check if fd is valid */
-       flags=fcntl(fd, F_GETFL);
+       do {
+               flags=fcntl(fd, F_GETFL);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(flags==-1) {
                /* Invalid fd.  Not really much point checking for EBADF
                 * specifically
index 5a15b61c60af4b519452cb8c6de3d3313aa9c07e..dedd4e2f6521c73517becd00f80badd7b42956bc 100644 (file)
@@ -424,7 +424,7 @@ gboolean CreateProcess (const gunichar2 *appname, gunichar2 *cmdline,
                process_info->dwProcessId=pid;
                process_info->dwThreadId=tid;
                /* Wait for possible execve failure */
-               if (WaitForSingleObject  (process_handle, 500) != WAIT_TIMEOUT) {
+               if (WaitForSingleObjectEx (process_handle, 500, FALSE) != WAIT_TIMEOUT) {
                        _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
                                             WAPI_HANDLE_PROCESS,
                                             (gpointer *) &process_handle_data,
index c47133e8eb50d022b602cc9b0b776447593e1d55..14849bd2f969657e26e72994cb632de756767b02 100644 (file)
@@ -122,6 +122,7 @@ gpointer _wapi_shm_file_expand (gpointer mem, _wapi_shm_t type,
        int fd;
        gpointer new_mem;
        guchar *filename=_wapi_shm_file (type, segment);
+       int ret;
 
        if(old_len>=new_len) {
                return(mem);
@@ -144,12 +145,18 @@ gpointer _wapi_shm_file_expand (gpointer mem, _wapi_shm_t type,
                return(NULL);
        }
        
-       if(write (fd, "", 1)==-1) {
+       do {
+               ret=write (fd, "", 1);
+       }
+       while (ret==-1 && errno==EINTR);
+
+       if(ret==-1) {
                g_critical (G_GNUC_PRETTY_FUNCTION
                            ": shared file [%s] write error: %s", filename,
                            g_strerror (errno));
                return(NULL);
        }
+
        close (fd);
        
        new_mem=_wapi_shm_file_map (type, segment, NULL, NULL);
@@ -163,6 +170,7 @@ static int _wapi_shm_file_open (const guchar *filename, _wapi_shm_t type,
        int fd;
        struct stat statbuf;
        guint32 wanted_size = 0;
+       int ret;
        
        if(created) {
                *created=FALSE;
@@ -215,7 +223,12 @@ try_again:
                                return(-1);
                        }
                        
-                       if(write (fd, "", 1)==-1) {
+                       do {
+                               ret=write (fd, "", 1);
+                       }
+                       while (ret==-1 && errno==EINTR);
+                               
+                       if(ret==-1) {
                                g_critical (G_GNUC_PRETTY_FUNCTION ": shared file [%s] write error: %s", filename, g_strerror (errno));
                                close (fd);
                                unlink (filename);
index d3d717c17516ac60281c810d360a4f6f116dc797..3f48f02af8e4328a8fb127ae1b8ef6f222e7f6b8 100644 (file)
@@ -97,7 +97,11 @@ static void socket_close_private (gpointer handle)
 
        g_ptr_array_remove_fast(sockets, GUINT_TO_POINTER (handle));
 
-       ret=close(socket_private_handle->fd);
+       do {
+               ret=close(socket_private_handle->fd);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+       
        if(ret==-1) {
                gint errnum = errno;
 #ifdef DEBUG
@@ -232,7 +236,11 @@ guint32 _wapi_accept(guint32 handle, struct sockaddr *addr,
                return(INVALID_SOCKET);
        }
        
-       fd=accept(socket_private_handle->fd, addr, addrlen);
+       do {
+               fd=accept(socket_private_handle->fd, addr, addrlen);
+       }
+       while (fd==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(fd==-1) {
                gint errnum = errno;
 #ifdef DEBUG
@@ -340,7 +348,11 @@ int _wapi_connect(guint32 handle, const struct sockaddr *serv_addr,
                return(SOCKET_ERROR);
        }
        
-       ret=connect(socket_private_handle->fd, serv_addr, addrlen);
+       do {
+               ret=connect(socket_private_handle->fd, serv_addr, addrlen);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(ret==-1 && errno==EACCES) {
                /* Try setting SO_BROADCAST and connecting again, but
                 * keep the original errno
@@ -352,8 +364,10 @@ int _wapi_connect(guint32 handle, const struct sockaddr *serv_addr,
                ret=setsockopt (socket_private_handle->fd, SOL_SOCKET,
                                SO_BROADCAST, &true, sizeof(true));
                if(ret==0) {
-                       ret=connect (socket_private_handle->fd, serv_addr,
-                                    addrlen);
+                       do {
+                               ret=connect (socket_private_handle->fd, serv_addr, addrlen);
+                       }
+                       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
                }
        } else if (ret==-1) {
                errnum = errno;
@@ -554,12 +568,18 @@ int _wapi_recvfrom(guint32 handle, void *buf, size_t len, int recv_flags,
        }
        
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=recvfrom(socket_private_handle->fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
-                    fromlen);
+       do {
+               ret=recvfrom(socket_private_handle->fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
+                            fromlen);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
 #else
        old_sigpipe = signal(SIGPIPE, SIG_IGN);
-       ret=recvfrom(socket_private_handle->fd, buf, len, recv_flags, from,
-                    fromlen);
+       do {
+               ret=recvfrom(socket_private_handle->fd, buf, len, recv_flags, from,
+                            fromlen);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
        signal(SIGPIPE, old_sigpipe);
 #endif
 
@@ -602,10 +622,16 @@ int _wapi_send(guint32 handle, const void *msg, size_t len, int send_flags)
        }
 
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=send(socket_private_handle->fd, msg, len, send_flags | MSG_NOSIGNAL);
+       do {
+               ret=send(socket_private_handle->fd, msg, len, send_flags | MSG_NOSIGNAL);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
 #else
        old_sigpipe = signal(SIGPIPE, SIG_IGN);
-       ret=send(socket_private_handle->fd, msg, len, send_flags);
+       do {
+               ret=send(socket_private_handle->fd, msg, len, send_flags);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
        signal(SIGPIPE, old_sigpipe);
 #endif
        if(ret==-1) {
@@ -648,10 +674,16 @@ int _wapi_sendto(guint32 handle, const void *msg, size_t len, int send_flags,
        }
        
 #ifdef HAVE_MSG_NOSIGNAL
-       ret=sendto(socket_private_handle->fd, msg, len, send_flags | MSG_NOSIGNAL, to, tolen);
+       do {
+               ret=sendto(socket_private_handle->fd, msg, len, send_flags | MSG_NOSIGNAL, to, tolen);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
 #else
        old_sigpipe = signal(SIGPIPE, SIG_IGN);
-       ret=sendto(socket_private_handle->fd, msg, len, send_flags, to, tolen);
+       do {
+               ret=sendto(socket_private_handle->fd, msg, len, send_flags, to, tolen);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
        signal(SIGPIPE, old_sigpipe);
 #endif
        if(ret==-1) {
@@ -984,7 +1016,11 @@ int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
                return(SOCKET_ERROR);
        }
 
-       ret=select(getdtablesize(), readfds, writefds, exceptfds, timeout);
+       do {
+               ret=select(getdtablesize(), readfds, writefds, exceptfds, timeout);
+       }
+       while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
+
        if(ret==-1) {
                gint errnum = errno;
 #ifdef DEBUG
index 951d547030f9958b0b49cd0eff125749ed36fe12..93a38f21d5249dfd1e77d8c296e686927bd40a9c 100644 (file)
@@ -35,4 +35,9 @@ struct _WapiHandlePrivate_thread
        gboolean joined;
 };
 
+gboolean _wapi_thread_apc_pending (gpointer handle);
+gboolean _wapi_thread_cur_apc_pending (void);
+gboolean _wapi_thread_dispatch_apc_queue (gpointer handle);
+
+
 #endif /* _WAPI_THREAD_PRIVATE_H_ */
index 877e0245a60b6cd94dd5b747a03a6345698762ed..773cbb016b8c65819252fec8917f9a93db23b15a 100644 (file)
@@ -12,6 +12,7 @@
 #include <mono/os/gc_wrapper.h>
 #include "mono/utils/mono-hash.h"
 #endif
+#include <stdio.h>
 #include <glib.h>
 #include <string.h>
 #include <pthread.h>
@@ -913,6 +914,71 @@ BindIoCompletionCallback (gpointer handle,
        return FALSE;
 }
 
+guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer handle, 
+                                       gpointer param)
+{
+       struct _WapiHandle_thread *thread_handle;
+       struct _WapiHandlePrivate_thread *thread_private_handle;
+       gboolean ok;
+
+       ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+                               (gpointer *)&thread_handle,
+                               (gpointer *)&thread_private_handle);
+       if(ok==FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up thread handle %p", handle);
+               return(0);
+       }
+
+       _wapi_timed_thread_queue_apc (thread_private_handle->thread, 
+                                                       apc_callback, param);
+       return(1);
+}
+
+gboolean _wapi_thread_cur_apc_pending (void)
+{
+       return _wapi_thread_apc_pending (GetCurrentThread ());
+}
+
+gboolean _wapi_thread_apc_pending (gpointer handle)
+{
+       struct _WapiHandle_thread *thread_handle;
+       struct _WapiHandlePrivate_thread *thread_private_handle;
+       gboolean ok;
+
+       ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+                               (gpointer *)&thread_handle,
+                               (gpointer *)&thread_private_handle);
+       if(ok==FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up thread handle %p", handle);
+               return(FALSE);
+       }
+
+       return _wapi_timed_thread_apc_pending (thread_private_handle->thread);
+}
+
+gboolean _wapi_thread_dispatch_apc_queue (gpointer handle)
+{
+       struct _WapiHandle_thread *thread_handle;
+       struct _WapiHandlePrivate_thread *thread_private_handle;
+       gboolean ok;
+
+       ok=_wapi_lookup_handle (handle, WAPI_HANDLE_THREAD,
+                               (gpointer *)&thread_handle,
+                               (gpointer *)&thread_private_handle);
+       if(ok==FALSE) {
+               g_warning (G_GNUC_PRETTY_FUNCTION
+                          ": error looking up thread handle %p", handle);
+               return(0);
+       }
+
+       _wapi_timed_thread_dispatch_apc_queue (thread_private_handle->thread);
+       return(1);
+}
+
+
+
 #ifdef WITH_INCLUDED_LIBGC
 
 static void GC_suspend_handler (int sig)
index 58e82d5a3be10a1e686f7913fe4a842436c7c2a6..6b67265bb7a878066f31a4516906de1321192ff3 100644 (file)
@@ -36,6 +36,7 @@
 #define THREAD_ALL_ACCESS              (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff)
 
 typedef guint32 (*WapiThreadStart)(gpointer);
+typedef guint32 (*WapiApcProc)(gpointer);
 
 extern gpointer CreateThread(WapiSecurityAttributes *security,
                             guint32 stacksize, WapiThreadStart start,
@@ -57,4 +58,7 @@ extern gboolean BindIoCompletionCallback (gpointer handle,
                                          WapiOverlappedCB callback,
                                          guint64 flags);
 
+extern guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer thread_handle, 
+                                       gpointer param);
+
 #endif /* _WAPI_THREADS_H_ */
index 371e704616a86251f09347bef236a0c4379f3fd9..76df37bff775aea9813526ee5db3c1ed0476a90e 100644 (file)
@@ -30,6 +30,8 @@
 
 static pthread_key_t timed_thread_key;
 static mono_once_t timed_thread_once = MONO_ONCE_INIT;
+static mono_mutex_t apc_mutex;
+
 
 static void timed_thread_init(void)
 {
@@ -37,6 +39,9 @@ static void timed_thread_init(void)
        
        thr_ret = pthread_key_create(&timed_thread_key, NULL);
        g_assert (thr_ret == 0);
+       
+       thr_ret = mono_mutex_init(&apc_mutex, NULL);
+       g_assert (thr_ret == 0);
 }
 
 void _wapi_timed_thread_exit(guint32 exitstatus)
@@ -159,6 +164,7 @@ int _wapi_timed_thread_create(TimedThread **threadp,
        thread->exit_userdata = exit_userdata;
        thread->exitstatus = 0;
        thread->exiting = FALSE;
+       thread->apc_queue = NULL;
        
        *threadp = thread;
 
@@ -296,3 +302,57 @@ void _wapi_timed_thread_resume (TimedThread *thread)
 {
        MONO_SEM_POST (&thread->suspend_sem);
 }
+
+void _wapi_timed_thread_queue_apc (TimedThread *thread, 
+       guint32 (*apc_callback)(gpointer), gpointer param)
+{
+       ApcInfo *apc;
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&apc_mutex);
+       thr_ret = mono_mutex_lock(&apc_mutex);
+       g_assert (thr_ret == 0);
+       
+       apc = (ApcInfo *)g_new(ApcInfo, 1);
+       apc->callback = apc_callback;
+       apc->param = param;
+       thread->apc_queue = g_slist_append (thread->apc_queue, apc);
+
+       thr_ret = mono_mutex_unlock(&apc_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
+}
+
+gboolean _wapi_timed_thread_apc_pending (TimedThread *thread)
+{
+       return thread->apc_queue != NULL;
+}
+
+void _wapi_timed_thread_dispatch_apc_queue (TimedThread *thread)
+{
+       ApcInfo* apc;
+       GSList *list;
+       int thr_ret;
+
+       pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
+                             (void *)&apc_mutex);
+       thr_ret = mono_mutex_lock(&apc_mutex);
+       g_assert (thr_ret == 0);
+       
+       list = thread->apc_queue;
+       thread->apc_queue = NULL;
+
+       thr_ret = mono_mutex_unlock(&apc_mutex);
+       g_assert (thr_ret == 0);
+       pthread_cleanup_pop (0);
+       
+       while (list != NULL) {
+               apc = (ApcInfo*)list->data;
+               apc->callback (apc->param);
+               g_free (apc);
+               list = g_slist_next (list);
+       }
+       g_slist_free (list);
+}
+
index de2837a52500efb888c2717c6a67225665b25ac1..a656f8b8221cd5370f81d8667b160e3857ab1a00 100644 (file)
@@ -51,8 +51,15 @@ typedef struct
        guint32 exitstatus;
        gboolean exiting;
        gpointer stack_ptr;
+       GSList *apc_queue;
 } TimedThread;
 
+typedef struct
+{
+       guint32 (*callback)(gpointer arg);
+       gpointer param;
+} ApcInfo;
+
 extern void _wapi_timed_thread_exit(guint32 exitstatus) G_GNUC_NORETURN;
 extern int _wapi_timed_thread_create(TimedThread **threadp,
                                     const pthread_attr_t *attr,
@@ -69,5 +76,11 @@ extern int _wapi_timed_thread_join(TimedThread *thread,
 extern void _wapi_timed_thread_destroy (TimedThread *thread);
 extern void _wapi_timed_thread_suspend (TimedThread *thread);
 extern void _wapi_timed_thread_resume (TimedThread *thread);
+                                  
+extern void _wapi_timed_thread_queue_apc (TimedThread *thread, 
+                                       guint32 (*apc_callback)(gpointer), gpointer param);
+extern gboolean _wapi_timed_thread_apc_pending (TimedThread *thread);
+extern void _wapi_timed_thread_dispatch_apc_queue (TimedThread *thread);
+                  
 
 #endif /* _WAPI_TIMED_THREAD_H_ */
index 39634c7596629bede629c48ad85c7ea731061571..f7055de04d0d1af694bfd3d56e616a387779b076 100644 (file)
@@ -67,6 +67,7 @@ typedef WapiStartupInfo STARTUPINFO;
 typedef WapiStartupInfo *LPSTARTUPINFO;
 typedef WapiProcessInformation PROCESS_INFORMATION;
 typedef WapiFixedFileInfo VS_FIXEDFILEINFO;
+typedef WapiApcProc PAPCFUNC;
 
 #define CONST const
 #define VOID void
index c579e94bc0b2b980eda9c70004df4b964325eecc..f4b77e6ab0e7a9e82a52aafa36e277cf437601f7 100644 (file)
 #undef DEBUG
 
 /**
- * WaitForSingleObject:
+ * WaitForSingleObjectEx:
  * @handle: an object to wait for
  * @timeout: the maximum time in milliseconds to wait for
+ * @alertable: if TRUE, the wait can be interrupted by an APC call
  *
  * This function returns when either @handle is signalled, or @timeout
  * ms elapses.  If @timeout is zero, the object's state is tested and
  * to nonsignalled.  %WAIT_OBJECT_0 - The state of @handle is
  * signalled.  %WAIT_TIMEOUT - The @timeout interval elapsed and
  * @handle's state is still not signalled.  %WAIT_FAILED - an error
- * occurred.
+ * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC.
  */
-guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
+guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout,
+                                               gboolean alertable)
 {
        guint32 ret, waited;
        struct timespec abstime;
        int thr_ret;
+       gboolean apc_pending = FALSE;
+       gpointer current_thread = GetCurrentThread ();
        
        if(_wapi_handle_test_capabilities (handle,
                                           WAPI_HANDLE_CAP_WAIT)==FALSE) {
@@ -78,6 +82,11 @@ guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
                }
        }
        
+       if (alertable && _wapi_thread_apc_pending (current_thread)) {
+               apc_pending = TRUE;
+               goto done;
+       }
+       
        if(_wapi_handle_issignalled (handle)) {
 #ifdef DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION
@@ -101,8 +110,11 @@ guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
                        waited=_wapi_handle_timedwait_signal_handle (handle,
                                                                     &abstime);
                }
+       
+               if (alertable)
+                       apc_pending = _wapi_thread_apc_pending (current_thread);
 
-               if(waited==0) {
+               if(waited==0 && !apc_pending) {
                        /* Condition was signalled, so hopefully
                         * handle is signalled now.  (It might not be
                         * if someone else got in before us.)
@@ -120,7 +132,7 @@ guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
                
                        /* Better luck next time */
                }
-       } while(waited==0);
+       } while(waited==0 && !apc_pending);
 
        /* Timeout or other error */
 #ifdef DEBUG
@@ -140,9 +152,20 @@ done:
        g_assert (thr_ret == 0);
        pthread_cleanup_pop (0);
        
+       if (apc_pending) {
+               _wapi_thread_dispatch_apc_queue (current_thread);
+               ret = WAIT_IO_COMPLETION;
+       }
+               
        return(ret);
 }
 
+guint32 WaitForSingleObject(gpointer handle, guint32 timeout)
+{
+       return WaitForSingleObjectEx (handle, timeout, FALSE);
+}
+
+
 /**
  * SignalObjectAndWait:
  * @signal_handle: An object to signal
@@ -184,6 +207,8 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
        guint32 ret, waited;
        struct timespec abstime;
        int thr_ret;
+       gboolean apc_pending = FALSE;
+       gpointer current_thread = GetCurrentThread ();
        
        if(_wapi_handle_test_capabilities (signal_handle,
                                           WAPI_HANDLE_CAP_SIGNAL)==FALSE) {
@@ -218,6 +243,11 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                }
        }
        
+       if (alertable && _wapi_thread_apc_pending (current_thread)) {
+               apc_pending = TRUE;
+               goto done;
+       }
+       
        if(_wapi_handle_issignalled (wait)) {
 #ifdef DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION
@@ -242,7 +272,10 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                                                                     &abstime);
                }
 
-               if(waited==0) {
+               if (alertable)
+                       apc_pending = _wapi_thread_apc_pending (current_thread);
+
+               if(waited==0 && !apc_pending) {
                        /* Condition was signalled, so hopefully
                         * handle is signalled now.  (It might not be
                         * if someone else got in before us.)
@@ -260,7 +293,7 @@ guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                
                        /* Better luck next time */
                }
-       } while(waited==0);
+       } while(waited==0 && !apc_pending);
 
        /* Timeout or other error */
 #ifdef DEBUG
@@ -280,8 +313,9 @@ done:
        g_assert (thr_ret == 0);
        pthread_cleanup_pop (0);
 
-       if(alertable==TRUE) {
-               /* Deal with queued APC or IO completion routines */
+       if (apc_pending) {
+               _wapi_thread_dispatch_apc_queue (current_thread);
+               ret = WAIT_IO_COMPLETION;
        }
        
        return(ret);
@@ -336,7 +370,7 @@ static gboolean test_and_own (guint32 numobjects, gpointer *handles,
 
 
 /**
- * WaitForMultipleObjects:
+ * WaitForMultipleObjectsEx:
  * @numobjects: The number of objects in @handles. The maximum allowed
  * is %MAXIMUM_WAIT_OBJECTS.
  * @handles: An array of object handles.  Duplicates are not allowed.
@@ -344,6 +378,7 @@ static gboolean test_and_own (guint32 numobjects, gpointer *handles,
  * are signalled.  If %FALSE, this function returns when any object is
  * signalled.
  * @timeout: The maximum time in milliseconds to wait for.
+ * @alertable: if TRUE, the wait can be interrupted by an APC call
  * 
  * This function returns when either one or more of @handles is
  * signalled, or @timeout ms elapses.  If @timeout is zero, the state
@@ -362,9 +397,10 @@ static gboolean test_and_own (guint32 numobjects, gpointer *handles,
  * indicates the first index into @handles of an abandoned mutex.
  * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in
  * @handles are signalled.  %WAIT_FAILED - an error occurred.
+ * %WAIT_IO_COMPLETION - the wait was ended by an APC.
  */
-guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
-                              gboolean waitall, guint32 timeout)
+guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
+                              gboolean waitall, guint32 timeout, gboolean alertable)
 {
        GHashTable *dups;
        gboolean duplicate=FALSE, bogustype=FALSE, done;
@@ -373,6 +409,7 @@ guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
        guint i;
        guint32 ret;
        int thr_ret;
+       gpointer current_thread = GetCurrentThread ();
        
        if(numobjects>MAXIMUM_WAIT_OBJECTS) {
 #ifdef DEBUG
@@ -384,7 +421,7 @@ guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
        }
        
        if (numobjects == 1) {
-               return WaitForSingleObject (handles [0], timeout);
+               return WaitForSingleObjectEx (handles [0], timeout, alertable);
        }
 
        /* Check for duplicates */
@@ -445,6 +482,11 @@ guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
                _wapi_calc_timeout (&abstime, timeout);
        }
 
+       if (alertable && _wapi_thread_apc_pending (current_thread)) {
+               _wapi_thread_dispatch_apc_queue (current_thread);
+               return WAIT_IO_COMPLETION;
+       }
+       
        while(1) {
 #ifdef DEBUG
                g_message (G_GNUC_PRETTY_FUNCTION ": locking signal mutex");
@@ -468,6 +510,11 @@ guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
                g_assert (thr_ret == 0);
                pthread_cleanup_pop (0);
                
+               if (alertable && _wapi_thread_apc_pending (current_thread)) {
+                       _wapi_thread_dispatch_apc_queue (current_thread);
+                       return WAIT_IO_COMPLETION;
+               }
+       
                if(ret==0) {
                        /* Something was signalled ... */
                        done = test_and_own (numobjects, handles, waitall,
@@ -489,3 +536,9 @@ guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
                }
        }
 }
+
+guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
+                              gboolean waitall, guint32 timeout)
+{
+       return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
+}
index 5c0111c758ea98bf3c085b86e424427421ce84b6..9eec987ea8099d5e6ad535d86ac8f958a4cae871 100644 (file)
 #define WAIT_IO_COMPLETION     STATUS_USER_APC
 
 extern guint32 WaitForSingleObject(gpointer handle, guint32 timeout);
+extern guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout, 
+                                       gboolean alertable);
 extern guint32 SignalObjectAndWait(gpointer signal_handle, gpointer wait,
                                   guint32 timeout, gboolean alertable);
 extern guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
                                      gboolean waitall, guint32 timeout);
+extern guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles,
+                                     gboolean waitall, guint32 timeout, gboolean alertable);
 
 #endif /* _WAPI_WAIT_H_ */