diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2011-04-28 12:13:41 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2011-04-28 12:13:41 +0000 |
commit | 86bf572ef07171999788f0358340c28a1e7ce159 (patch) | |
tree | 2dd2f3e3cda7b51b9fd62f3e5a611cb0af08d52e /winsup/cygwin/posix_ipc.cc | |
parent | 1838d97b0a27fba6511ee718d527e93000231587 (diff) | |
download | cygnal-86bf572ef07171999788f0358340c28a1e7ce159.tar.gz cygnal-86bf572ef07171999788f0358340c28a1e7ce159.tar.bz2 cygnal-86bf572ef07171999788f0358340c28a1e7ce159.zip |
* 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.
Diffstat (limited to 'winsup/cygwin/posix_ipc.cc')
-rw-r--r-- | winsup/cygwin/posix_ipc.cc | 119 |
1 files changed, 84 insertions, 35 deletions
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; - - if (!abstime) - timeout = INFINITE; - else if (abstime->tv_sec < 0 - || abstime->tv_nsec < 0 - || abstime->tv_nsec > 999999999) - return EINVAL; - else + HANDLE w4[3] = { evt, signal_arrived, NULL }; + DWORD cnt = 2; + int ret = 0; + + 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--; |