[PATCH 8/8] ntdll: add ability to trywait on semaphores locally
Daniel Santos
daniel.santos at pobox.com
Thu Sep 10 01:34:56 CDT 2015
server_select can now trywait on native semaphores in a select_op when
wait conditions do not require the thread to block. Otherwise, a
standard server call is made.
Signed-off-by: Daniel Santos <daniel.santos at pobox.com>
---
dlls/ntdll/server.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index 763a90d..997954c 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -83,6 +83,7 @@
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(server);
+WINE_DECLARE_DEBUG_CHANNEL(ntdllsync);
/* Some versions of glibc don't define this */
#ifndef SCM_RIGHTS
@@ -594,6 +595,136 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
memset( &result, 0, sizeof(result) );
+#if ENABLE_POSIX_SYNC
+ TRACE_(ntdllsync)("select_op = %p, size = %u, flags = 0x%x, timeout = %p (%zd)\n",
+ select_op, size, flags, timeout, (timeout ? timeout->QuadPart : 0));
+
+ if (select_op && (select_op->op == SELECT_WAIT || select_op->op == SELECT_WAIT_ALL))
+ {
+ struct ntdll_object *objs[MAXIMUM_WAIT_OBJECTS];
+ size_t nb_locally_lockable_objs = 0;
+ size_t nb_handles = (size - offsetof( select_op_t, wait.handles ))
+ / sizeof(select_op->wait.handles[0]);
+ ssize_t i;
+ NTSTATUS result;
+ NTSTATUS ret = STATUS_UNSUCCESSFUL;
+
+ /* count the number of locally lockable objects & cache their pointers */
+ for (i = 0; i < nb_handles; ++i)
+ {
+ objs[i] = ntdll_handle_find(wine_server_ptr_handle(select_op->wait.handles[i]));
+ if (objs[i] && objs[i]->ops->trywait)
+ ++nb_locally_lockable_objs;
+ }
+
+ TRACE_(ntdllsync)("%zd/%zd objects are locally selectable, need %s.\n",
+ nb_locally_lockable_objs, nb_handles,
+ (select_op->op == SELECT_WAIT ? "any" : "all"));
+
+ /* bWaitAll = FALSE */
+ if (select_op->op == SELECT_WAIT)
+ {
+ if (!nb_locally_lockable_objs)
+ goto local_done;
+
+ /* waitformultipleobjectsex with bWaitAll = FALSE must go in order */
+ for (i = 0; i < nb_handles; ++i)
+ {
+ /* If we can't lock this one locally, we must do the server call */
+ if (!objs[i] || !objs[i]->ops->trywait)
+ break;
+
+ result = objs[i]->ops->trywait(objs[i]);
+ if (result == STATUS_SUCCESS)
+ {
+ TRACE_(ntdllsync)("Successful local wait any. obj = %p (h = %p)\n", objs[i], objs[i]->h);
+
+ ret = STATUS_SUCCESS;
+ break;
+ }
+ else if (result == STATUS_WAS_LOCKED)
+ continue;
+ else
+ ret = result;
+ }
+ }
+
+ else /* select_op->op == SELECT_WAIT_ALL (bWaitAll = TRUE)*/
+ {
+ ULONGLONG locked_objs = 0;
+ assert(MAXIMUM_WAIT_OBJECTS <= sizeof(locked_objs) * 8);
+
+ if (nb_locally_lockable_objs != nb_handles)
+ goto local_done;
+
+ result = 0;
+
+ /* try to lock all objects */
+ for (i = 0; i < nb_handles; ++i)
+ {
+ result = objs[i]->ops->trywait(objs[i]);
+
+ if (result == STATUS_WAS_LOCKED) /* normal trywait failure */
+ break;
+ else if (result != STATUS_POSSIBLE_DEADLOCK)
+ {
+ WARN("Possible deadlock in thread 0x%x, waiting on handle %p\n", GetCurrentThreadId(), objs[i]->h);
+ break;
+ }
+ else if (result != STATUS_SUCCESS)
+ {
+ ERR("object (handle = %p) trywait returned 0x%x\n", objs[i]->h, result);
+ break;
+ }
+
+ /* keep track of the objects we've locked, max 64 */
+ locked_objs |= 1LL << i;
+ TRACE_(ntdllsync)("locked object %zd/%zd\n", i, nb_handles);
+ }
+
+ /* This is a little redundant, if result == STATUS_SUCCESS, then i should also be == nb_handles */
+ if (result == STATUS_SUCCESS && i == nb_handles)
+ {
+ TRACE_(ntdllsync)("Successful local wait all. count = %zu\n", nb_handles);
+ ret = STATUS_SUCCESS;
+ }
+ /* if not successful then roll back locks */
+ else
+ {
+ TRACE_(ntdllsync)("rolling back...\n");
+ for (; i >= 0; --i)
+ {
+ TRACE_(ntdllsync)("rolling back %zd/%zd\n", i, nb_handles);
+ if (locked_objs & (1 << i))
+ objs[i]->ops->trywait_undo(objs[i]);
+ }
+
+ if (result != STATUS_WAS_LOCKED)
+ return result;
+ }
+ }
+
+local_done:
+
+ /* release any objects we've grabbed */
+ for (i = 0; i < nb_handles; ++i)
+ if (objs[i])
+ ntdll_object_release(objs[i]);
+
+ switch (ret)
+ {
+ case STATUS_SUCCESS:
+ return STATUS_SUCCESS;
+
+ default:
+ /* fall through to server call */
+ break;
+ }
+ }
+TRACE_(ntdllsync)("Doing server call.\n");
+
+#endif /* ENABLE_POSIX_SYNC */
+
for (;;)
{
SERVER_START_REQ( select )
--
2.4.6
More information about the wine-devel
mailing list