From 65522961f3a0cc382bf2effc445228815ee06e58 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 13 Nov 2015 22:39:00 +0100
Subject: server: Allow multiple registry notifications for the same key.

---
 dlls/ntdll/tests/reg.c |  6 ++---
 server/registry.c      | 53 ++++++++++++++++++++++--------------------
 2 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/dlls/ntdll/tests/reg.c b/dlls/ntdll/tests/reg.c
index 9bb8d2502..1ba688084 100644
--- a/dlls/ntdll/tests/reg.c
+++ b/dlls/ntdll/tests/reg.c
@@ -1874,7 +1874,7 @@ static void test_notify(void)
     pRtlFreeUnicodeString(&str);
 
     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);
 
@@ -1887,7 +1887,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);
 
@@ -1901,7 +1901,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 964e2ebd5..41af3cbe7 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -49,10 +49,16 @@
 
 #include "winternl.h"
 
+struct notify_event
+{
+    struct list      entry;     /* entry in list of events */
+    struct event    *event;     /* event to set */
+};
+
 struct notify
 {
     struct list       entry;    /* entry in list of notifications */
-    struct event     *event;    /* event to set when changing this key */
+    struct list       events;   /* list of events to set when changing this key */
     int               subtree;  /* true if subtree notification */
     unsigned int      filter;   /* which events to notify on */
     obj_handle_t      hkey;     /* hkey associated with this notification */
@@ -313,12 +319,17 @@ static struct object_type *key_get_type( struct object *obj )
 /* notify waiter and maybe delete the notification */
 static void do_notification( struct key *key, struct notify *notify, int del )
 {
-    if (notify->event)
+    void *ptr;
+
+    while ((ptr = list_head( &notify->events )))
     {
-        set_event( notify->event );
-        release_object( notify->event );
-        notify->event = NULL;
+        struct notify_event *notify_event = LIST_ENTRY( ptr, struct notify_event, entry );
+        list_remove( &notify_event->entry );
+        set_event( notify_event->event );
+        release_object( notify_event->event );
+        free( notify_event );
     }
+
     if (del)
     {
         list_remove( &notify->entry );
@@ -2277,6 +2288,7 @@ DECL_HANDLER(set_registry_notification)
     struct key *key;
     struct event *event;
     struct notify *notify;
+    struct notify_event *notify_event;
 
     key = get_hkey_obj( req->hkey, KEY_NOTIFY );
     if (key)
@@ -2285,29 +2297,20 @@ DECL_HANDLER(set_registry_notification)
         if (event)
         {
             notify = find_notify( key, current->process, req->hkey );
-            if (notify)
-            {
-                if (notify->event)
-                    release_object( notify->event );
-                grab_object( event );
-                notify->event = event;
-            }
-            else
+            if (!notify && (notify = mem_alloc( sizeof(*notify) )))
             {
-                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 );
-                }
+                list_init( &notify->events );
+                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)
+            if (notify && (notify_event = mem_alloc( sizeof(*notify_event) )))
             {
+                grab_object(event);
+                notify_event->event = event;
+                list_add_tail( &notify->events, &notify_event->entry );
                 reset_event( event );
                 set_error( STATUS_PENDING );
             }
-- 
2.23.0

