From 86bf572ef07171999788f0358340c28a1e7ce159 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 28 Apr 2011 12:13:41 +0000 Subject: [PATCH] * cygerrno.h (geterrno_from_nt_status): Declare. * errno.cc (geterrno_from_nt_status): Define. * flock.cc: Fix copyright dates. * ntdll.h (enum _TIMER_TYPE): Define. (PTIMER_APC_ROUTINE): Define. (NtCancelTimer): Declare. (NtCreateTimer): Declare. (NtSetTimer): Declare. * posix_ipc.cc (ipc_cond_timedwait): Rewrite to make interruptible and restartable. Call pthread_testcancel in case of timeout to enable pthread_cancel on waiting thread. Replace WFMO timeout with waiting for a waitable timer. Explain why. Replace single call to WFMO with two calls, one for the event, one for the mutex. Don't lock mutex in case of error. (ipc_cond_signal): Make void function. (ipc_cond_close): Ditto. (_mq_send): Immediately return -1 in case of error from ipc_cond_timedwait. (_mq_receive): Ditto. --- winsup/cygwin/ChangeLog | 22 +++++++ winsup/cygwin/cygerrno.h | 3 +- winsup/cygwin/errno.cc | 6 ++ winsup/cygwin/flock.cc | 2 +- winsup/cygwin/ntdll.h | 13 +++++ winsup/cygwin/posix_ipc.cc | 117 ++++++++++++++++++++++++++----------- 6 files changed, 127 insertions(+), 36 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index bd1381ce1..71c6dae49 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,25 @@ +2011-04-28 Corinna Vinschen + + * cygerrno.h (geterrno_from_nt_status): Declare. + * errno.cc (geterrno_from_nt_status): Define. + * flock.cc: Fix copyright dates. + * ntdll.h (enum _TIMER_TYPE): Define. + (PTIMER_APC_ROUTINE): Define. + (NtCancelTimer): Declare. + (NtCreateTimer): Declare. + (NtSetTimer): Declare. + * posix_ipc.cc (ipc_cond_timedwait): Rewrite to make interruptible and + restartable. Call pthread_testcancel in case of timeout to enable + pthread_cancel on waiting thread. Replace WFMO timeout with waiting + for a waitable timer. Explain why. Replace single call to WFMO with + two calls, one for the event, one for the mutex. Don't lock mutex in + case of error. + (ipc_cond_signal): Make void function. + (ipc_cond_close): Ditto. + (_mq_send): Immediately return -1 in case of error from + ipc_cond_timedwait. + (_mq_receive): Ditto. + 2011-04-28 Corinna Vinschen * advapi32.cc (GetSecurityDescriptorDacl): Remove. diff --git a/winsup/cygwin/cygerrno.h b/winsup/cygwin/cygerrno.h index e1a1af07d..e63a17cc5 100644 --- a/winsup/cygwin/cygerrno.h +++ b/winsup/cygwin/cygerrno.h @@ -1,6 +1,6 @@ /* cygerrno.h: main Cygwin header file. - Copyright 2000, 2001, 2002, 2003, 2004, 2010 Red Hat, Inc. + Copyright 2000, 2001, 2002, 2003, 2004, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -16,6 +16,7 @@ void __stdcall seterrno_from_win_error (const char *file, int line, DWORD code) void __stdcall seterrno_from_nt_status (const char *file, int line, NTSTATUS status) __attribute__ ((regparm(3))); void __stdcall seterrno (const char *, int line) __attribute__ ((regparm(2))); int __stdcall geterrno_from_win_error (DWORD code = GetLastError (), int deferrno = 13 /*EACCESS*/) __attribute__ ((regparm(2))); +int __stdcall geterrno_from_nt_status (NTSTATUS status, int deferrno = 13 /*EACCESS*/) __attribute__ ((regparm(2))); #define __seterrno() seterrno (__FILE__, __LINE__) #define __seterrno_from_win_error(val) seterrno_from_win_error (__FILE__, __LINE__, val) diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc index b83760926..0df53df63 100644 --- a/winsup/cygwin/errno.cc +++ b/winsup/cygwin/errno.cc @@ -327,6 +327,12 @@ seterrno_from_win_error (const char *file, int line, DWORD code) errno = _impure_ptr->_errno = geterrno_from_win_error (code, EACCES); } +int __stdcall +geterrno_from_nt_status (NTSTATUS status, int deferrno) +{ + return geterrno_from_win_error (RtlNtStatusToDosError (status)); +} + /* seterrno_from_nt_status: Given a NT status code, set errno as appropriate. */ void __stdcall diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 16e2911a6..90128175f 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1,6 +1,6 @@ /* flock.cc. NT specific implementation of advisory file locking. - Copyright 2003, 2008, 2009 Red Hat, Inc. + Copyright 2003, 2008, 2009, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 8f13e1c6c..e9ff11bf0 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -948,6 +948,14 @@ typedef struct _KEY_VALUE_PARTIAL_INFORMATION UCHAR Data[1]; } KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; +typedef enum _TIMER_TYPE +{ + NotificationTimer, + SynchronisationTimer +} TIMER_TYPE, *PTIMER_TYPE; + +typedef VOID (APIENTRY *PTIMER_APC_ROUTINE)(PVOID, ULONG, ULONG); + /* Function declarations for ntdll.dll. These don't appear in any standard Win32 header. */ @@ -970,6 +978,7 @@ extern "C" ULONG, PTOKEN_PRIVILEGES, PULONG); NTSTATUS NTAPI NtAllocateLocallyUniqueId (PLUID); NTSTATUS NTAPI NtAllocateUuids (PLARGE_INTEGER, PULONG, PULONG, PUCHAR); + NTSTATUS NTAPI NtCancelTimer (HANDLE, PBOOLEAN); NTSTATUS NTAPI NtClose (HANDLE); NTSTATUS NTAPI NtCommitTransaction (HANDLE, BOOLEAN); NTSTATUS NTAPI NtCreateDirectoryObject (PHANDLE, ACCESS_MASK, @@ -990,6 +999,8 @@ extern "C" PLARGE_INTEGER, ULONG, ULONG, HANDLE); NTSTATUS NTAPI NtCreateSemaphore (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, LONG, LONG); + NTSTATUS NTAPI NtCreateTimer (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, + TIMER_TYPE); NTSTATUS NTAPI NtCreateToken (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, TOKEN_TYPE, PLUID, PLARGE_INTEGER, PTOKEN_USER, PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER, @@ -1081,6 +1092,8 @@ extern "C" ULONG); NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); + NTSTATUS NTAPI NtSetTimer (HANDLE, PLARGE_INTEGER, PTIMER_APC_ROUTINE, PVOID, + BOOLEAN, LONG, PBOOLEAN); NTSTATUS NTAPI NtSetTimerResolution (ULONG, BOOLEAN, PULONG); NTSTATUS NTAPI NtSetValueKey (HANDLE, PUNICODE_STRING, ULONG, ULONG, PVOID, ULONG); diff --git a/winsup/cygwin/posix_ipc.cc b/winsup/cygwin/posix_ipc.cc index c7b2bc0fe..600fb0d19 100644 --- a/winsup/cygwin/posix_ipc.cc +++ b/winsup/cygwin/posix_ipc.cc @@ -174,55 +174,104 @@ ipc_cond_init (HANDLE *pevt, const char *name, char sr) static int ipc_cond_timedwait (HANDLE evt, HANDLE mtx, const struct timespec *abstime) { - struct timeval tv; - DWORD timeout; - HANDLE h[2] = { mtx, evt }; - int err; + HANDLE w4[3] = { evt, signal_arrived, NULL }; + DWORD cnt = 2; + int ret = 0; - if (!abstime) - timeout = INFINITE; - else if (abstime->tv_sec < 0 - || abstime->tv_nsec < 0 - || abstime->tv_nsec > 999999999) - return EINVAL; - else + if (abstime) { - gettimeofday (&tv, NULL); - /* Check for immediate timeout. */ - if (tv.tv_sec > abstime->tv_sec - || (tv.tv_sec == abstime->tv_sec - && tv.tv_usec > abstime->tv_nsec / 1000)) - return ETIMEDOUT; - timeout = (abstime->tv_sec - tv.tv_sec) * 1000; - timeout += (abstime->tv_nsec / 1000 - tv.tv_usec) / 1000; + if (abstime->tv_sec < 0 + || abstime->tv_nsec < 0 + || abstime->tv_nsec > 999999999) + return EINVAL; + + /* If a timeout is set, we create a waitable timer to wait for. + This is the easiest way to handle the absolute timeout value, given + that NtSetTimer also takes absolute times and given the double + dependency on evt *and* mtx, which requires to call WFMO twice. */ + NTSTATUS status; + LARGE_INTEGER duetime; + + status = NtCreateTimer (&w4[2], TIMER_ALL_ACCESS, NULL, + NotificationTimer); + if (!NT_SUCCESS (status)) + return geterrno_from_nt_status (status); + timespec_to_filetime (abstime, (FILETIME *) &duetime); + status = NtSetTimer (w4[2], &duetime, NULL, NULL, FALSE, 0, NULL); + if (!NT_SUCCESS (status)) + { + NtClose (w4[2]); + return geterrno_from_nt_status (status); + } + cnt = 3; } ResetEvent (evt); - if ((err = ipc_mutex_unlock (mtx)) != 0) - return err; - switch (WaitForMultipleObjects (2, h, TRUE, timeout)) + if ((ret = ipc_mutex_unlock (mtx)) != 0) + return ret; + /* Everything's set up, so now wait for the event to be signalled. */ +restart1: + switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE)) { case WAIT_OBJECT_0: - case WAIT_ABANDONED_0: - return 0; - case WAIT_TIMEOUT: - ipc_mutex_lock (mtx); - return ETIMEDOUT; + break; + case WAIT_OBJECT_0 + 1: + if (_my_tls.call_signal_handler ()) + goto restart1; + ret = EINTR; + break; + case WAIT_OBJECT_0 + 2: + pthread_testcancel (); + ret = ETIMEDOUT; + break; default: + ret = geterrno_from_win_error (); break; } - return geterrno_from_win_error (); + if (ret == 0) + { + /* At this point we need to lock the mutex. The wait is practically + the same as before, just that we now wait on the mutex instead of the + event. */ + restart2: + w4[0] = mtx; + switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE)) + { + case WAIT_OBJECT_0: + case WAIT_ABANDONED_0: + break; + case WAIT_OBJECT_0 + 1: + if (_my_tls.call_signal_handler ()) + goto restart2; + ret = EINTR; + break; + case WAIT_OBJECT_0 + 2: + pthread_testcancel (); + ret = ETIMEDOUT; + break; + default: + ret = geterrno_from_win_error (); + break; + } + } + if (w4[2]) + { + if (ret != ETIMEDOUT) + NtCancelTimer (w4[2], NULL); + NtClose (w4[2]); + } + return ret; } -static inline int +static inline void ipc_cond_signal (HANDLE evt) { - return SetEvent (evt) ? 0 : geterrno_from_win_error (); + SetEvent (evt); } -static inline int +static inline void ipc_cond_close (HANDLE evt) { - return CloseHandle (evt) ? 0 : geterrno_from_win_error (); + CloseHandle (evt); } class ipc_flock @@ -736,7 +785,7 @@ _mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio, if (ret != 0) { set_errno (ret); - goto err; + return -1; } } } @@ -851,7 +900,7 @@ _mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop, if (ret != 0) { set_errno (ret); - goto err; + return -1; } } mqhdr->mqh_nwait--;