[2/2] server: Allow multiple registry notifications per key.

Sebastian Lackner sebastian at fds-team.de
Tue Nov 10 16:01:54 CST 2015


Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---

After this patch there are still a couple of remaining problems:

* Notifications should wake up when the original thread calling NtNotifyChangeKey
  terminates.

* The WatchSubtree Flag and the filters parameter should be stored somewhere in the
  key object itself? It seems like its not possible to change it anymore after
  the first notification.

* Missing threadpool support.

 dlls/ntdll/tests/reg.c |    6 ++---
 server/registry.c      |   54 ++++++++++++++++++-------------------------------
 2 files changed, 23 insertions(+), 37 deletions(-)

diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c
index 5cd58b0..08f4ed6 100644
--- a/dlls/ntdll/tests/reg.c
+++ b/dlls/ntdll/tests/reg.c
@@ -1546,7 +1546,7 @@ static void test_notify(void)
     ok(status == STATUS_SUCCESS, "NtCreateKey failed: 0x%08x\n", status);
 
     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
-    todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
+    ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
 
@@ -1559,7 +1559,7 @@ static void test_notify(void)
     ok(status == STATUS_SUCCESS, "NtDeleteSubkey failed: %x\n", status);
 
     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
-    todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
+    ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
 
@@ -1573,7 +1573,7 @@ static void test_notify(void)
     pNtClose(key);
 
     status = pNtWaitForSingleObject(events[0], FALSE, &timeout);
-    todo_wine ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
+    ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
     status = pNtWaitForSingleObject(events[1], FALSE, &timeout);
     ok(status == STATUS_SUCCESS, "NtWaitForSingleObject returned %x\n", status);
 
diff --git a/server/registry.c b/server/registry.c
index 3c9ae70..05d5bde 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -316,17 +316,6 @@ static void do_notification( struct key *key, struct notify *notify, int del )
     }
 }
 
-static inline struct notify *find_notify( struct key *key, struct process *process, obj_handle_t hkey )
-{
-    struct notify *notify;
-
-    LIST_FOR_EACH_ENTRY( notify, &key->notify_list, struct notify, entry )
-    {
-        if (notify->process == process && notify->hkey == hkey) return notify;
-    }
-    return NULL;
-}
-
 static unsigned int key_map_access( struct object *obj, unsigned int access )
 {
     if (access & GENERIC_READ)    access |= KEY_READ;
@@ -388,8 +377,18 @@ static struct security_descriptor *key_get_sd( struct object *obj )
 static int key_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
 {
     struct key * key = (struct key *) obj;
-    struct notify *notify = find_notify( key, process, handle );
-    if (notify) do_notification( key, notify, 1 );
+    struct list *ptr;
+
+    LIST_FOR_EACH( ptr, &key->notify_list )
+    {
+        struct notify *notify = LIST_ENTRY( ptr, struct notify, entry );
+        if (notify->process != process) continue;
+        if (notify->hkey != handle) continue;
+        do_notification( key, notify, 1 );
+        /* restart at the head of the list, the wake_up could have killed some processes */
+        ptr = &key->notify_list;
+    }
+
     return 1;  /* ok to close */
 }
 
@@ -2268,30 +2267,17 @@ DECL_HANDLER(set_registry_notification)
         event = get_event_obj( current->process, req->event, SYNCHRONIZE );
         if (event)
         {
-            notify = find_notify( key, current->process, req->hkey );
+            notify = mem_alloc( sizeof(*notify) );
             if (notify)
             {
-                if (notify->event)
-                    release_object( notify->event );
                 grab_object( event );
-                notify->event = event;
-            }
-            else
-            {
-                notify = mem_alloc( sizeof(*notify) );
-                if (notify)
-                {
-                    grab_object( event );
-                    notify->event   = event;
-                    notify->subtree = req->subtree;
-                    notify->filter  = req->filter;
-                    notify->hkey    = req->hkey;
-                    notify->process = current->process;
-                    list_add_head( &key->notify_list, &notify->entry );
-                }
-            }
-            if (notify)
-            {
+                notify->event   = event;
+                notify->subtree = req->subtree;
+                notify->filter  = req->filter;
+                notify->hkey    = req->hkey;
+                notify->process = current->process;
+                list_add_head( &key->notify_list, &notify->entry );
+
                 reset_event( event );
                 set_error( STATUS_PENDING );
             }
-- 
2.6.2



More information about the wine-patches mailing list