From: Sebastian Lackner Subject: [2/2] server: Allow multiple registry notifications per key. Message-Id: <56426952.7070203@fds-team.de> Date: Tue, 10 Nov 2015 23:01:54 +0100 Signed-off-by: Sebastian Lackner --- 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, ¬ify->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, ¬ify->entry ); + reset_event( event ); set_error( STATUS_PENDING ); } -- 2.6.2