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
+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.
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!");
}
#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!");
g_assert_not_reached ();
}
}
-
+
ret = mono_mutex_unlock (&req_mutex);
g_assert (ret == 0);
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;
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));
}
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;
}
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
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
/* 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
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
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
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
": 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
for (;;) {
remain = read (src_fd, buf, buf_size);
+
if (remain < 0) {
- if (errno == EINTR) {
+ if (errno == EINTR && !_wapi_thread_cur_apc_pending()) {
continue;
}
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.");
#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
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,
int fd;
gpointer new_mem;
guchar *filename=_wapi_shm_file (type, segment);
+ int ret;
if(old_len>=new_len) {
return(mem);
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);
int fd;
struct stat statbuf;
guint32 wanted_size = 0;
+ int ret;
if(created) {
*created=FALSE;
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);
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
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
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
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;
}
#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
}
#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) {
}
#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) {
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
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_ */
#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>
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)
#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,
WapiOverlappedCB callback,
guint64 flags);
+extern guint32 QueueUserAPC (WapiApcProc apc_callback, gpointer thread_handle,
+ gpointer param);
+
#endif /* _WAPI_THREADS_H_ */
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)
{
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)
thread->exit_userdata = exit_userdata;
thread->exitstatus = 0;
thread->exiting = FALSE;
+ thread->apc_queue = NULL;
*threadp = 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);
+}
+
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,
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_ */
typedef WapiStartupInfo *LPSTARTUPINFO;
typedef WapiProcessInformation PROCESS_INFORMATION;
typedef WapiFixedFileInfo VS_FIXEDFILEINFO;
+typedef WapiApcProc PAPCFUNC;
#define CONST const
#define VOID void
#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) {
}
}
+ 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
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.)
/* Better luck next time */
}
- } while(waited==0);
+ } while(waited==0 && !apc_pending);
/* Timeout or other error */
#ifdef DEBUG
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
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) {
}
}
+ 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
&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.)
/* Better luck next time */
}
- } while(waited==0);
+ } while(waited==0 && !apc_pending);
/* Timeout or other error */
#ifdef DEBUG
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);
/**
- * 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.
* 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
* 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;
guint i;
guint32 ret;
int thr_ret;
+ gpointer current_thread = GetCurrentThread ();
if(numobjects>MAXIMUM_WAIT_OBJECTS) {
#ifdef DEBUG
}
if (numobjects == 1) {
- return WaitForSingleObject (handles [0], timeout);
+ return WaitForSingleObjectEx (handles [0], timeout, alertable);
}
/* Check for duplicates */
_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");
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,
}
}
}
+
+guint32 WaitForMultipleObjects(guint32 numobjects, gpointer *handles,
+ gboolean waitall, guint32 timeout)
+{
+ return WaitForMultipleObjectsEx(numobjects, handles, waitall, timeout, FALSE);
+}
#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_ */