Commit 803cee46 authored by Zebediah Figura's avatar Zebediah Figura Committed by Vitaly Lipatov

ntdll: Implement NtWaitForMultipleObjects().

parent 282c89a6
......@@ -22,6 +22,8 @@
#pragma makedep unix
#endif
#define _GNU_SOURCE
#include "config.h"
#include <assert.h>
......@@ -34,6 +36,12 @@
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#endif
#include <sys/types.h>
#include <unistd.h>
......@@ -287,6 +295,168 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev )
return STATUS_SUCCESS;
}
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
static LONGLONG update_timeout( ULONGLONG end )
{
LARGE_INTEGER now;
LONGLONG timeleft;
NtQuerySystemTime( &now );
timeleft = end - now.QuadPart;
if (timeleft < 0) timeleft = 0;
return timeleft;
}
static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end )
{
if (end)
{
LONGLONG timeleft = update_timeout( *end );
#ifdef HAVE_PPOLL
/* We use ppoll() if available since the time granularity is better. */
struct timespec tmo_p;
tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100;
return ppoll( fds, nfds, &tmo_p, NULL );
#else
return poll( fds, nfds, timeleft / TICKSPERMSEC );
#endif
}
else
return poll( fds, nfds, -1 );
}
static void update_grabbed_object( struct esync *obj )
{
if (obj->type == ESYNC_SEMAPHORE)
{
struct semaphore *semaphore = obj->shm;
/* We don't have to worry about a race between this and read(); the
* fact that we were able to grab it at all means the count is nonzero,
* and if someone else grabbed it then the count must have been >= 2,
* etc. */
InterlockedExchangeAdd( &semaphore->count, -1 );
}
}
/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
* need to delegate to server_select(). */
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout )
{
struct esync *objs[MAXIMUM_WAIT_OBJECTS];
struct pollfd fds[MAXIMUM_WAIT_OBJECTS];
int has_esync = 0, has_server = 0;
LONGLONG timeleft;
LARGE_INTEGER now;
ULONGLONG end;
int i, ret;
NtQuerySystemTime( &now );
if (timeout)
{
if (timeout->QuadPart == TIMEOUT_INFINITE)
timeout = NULL;
else if (timeout->QuadPart >= 0)
end = timeout->QuadPart;
else
end = now.QuadPart - timeout->QuadPart;
}
for (i = 0; i < count; i++)
{
if ((objs[i] = get_cached_object( handles[i] )))
has_esync = 1;
else
has_server = 1;
}
if (has_esync && has_server)
FIXME("Can't wait on esync and server objects at the same time!\n");
else if (has_server)
return STATUS_NOT_IMPLEMENTED;
if (TRACE_ON(esync))
{
TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", count);
for (i = 0; i < count; i++)
TRACE(" %p", handles[i]);
if (!timeout)
TRACE(", timeout = INFINITE.\n");
else
{
timeleft = update_timeout( end );
TRACE(", timeout = %ld.%07ld sec.\n",
(long) timeleft / TICKSPERSEC, (long) timeleft % TICKSPERSEC);
}
}
if (wait_any || count == 1)
{
for (i = 0; i < count; i++)
{
fds[i].fd = objs[i] ? objs[i]->fd : -1;
fds[i].events = POLLIN;
}
while (1)
{
ret = do_poll( fds, count, timeout ? &end : NULL );
if (ret > 0)
{
/* Find out which object triggered the wait. */
for (i = 0; i < count; i++)
{
struct esync *obj = objs[i];
if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL))
{
ERR("Polling on fd %d returned %#x.\n", fds[i].fd, fds[i].revents);
return STATUS_INVALID_HANDLE;
}
if (obj)
{
int64_t value;
ssize_t size;
if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value))
{
/* We found our object. */
TRACE("Woken up by handle %p [%d].\n", handles[i], i);
update_grabbed_object( obj );
return i;
}
}
}
/* If we got here, someone else stole (or reset, etc.) whatever
* we were waiting for. So keep waiting. */
NtQuerySystemTime( &now );
}
else if (ret == 0)
{
TRACE("Wait timed out.\n");
return STATUS_TIMEOUT;
}
else
{
ERR("ppoll failed: %s\n", strerror( errno ));
return errno_to_status( errno );
}
}
}
else
{
FIXME("Wait-all not implemented.\n");
return STATUS_NOT_IMPLEMENTED;
}
}
void esync_init(void)
{
struct stat st;
......
......@@ -26,6 +26,9 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN;
extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN;
extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
/* We have to synchronize on the fd cache mutex so that our calls to receive_fd
* don't race with theirs. It looks weird, I know.
......
......@@ -1429,6 +1429,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO
if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
if (do_esync())
{
NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout );
if (ret != STATUS_NOT_IMPLEMENTED)
return ret;
}
if (alertable) flags |= SELECT_ALERTABLE;
select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment