* 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.
This commit is contained in:
Corinna Vinschen
2011-04-28 12:13:41 +00:00
parent 1838d97b0a
commit 86bf572ef0
6 changed files with 127 additions and 36 deletions

View File

@ -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--;