mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-01 00:42:16 +01:00 
			
		
		
		
	registrybackend: make subscribe and unsubscribe thread-safe
The registry backend uses a thread to monitor registry changes and send notifications. The state of this thread and structures used for communicating with it are kept in the watch variable. The subscribe and unsubscribe functions might be concurrently called from multiple threads and need to communicate with the monitoring thread. For this reason we need to synchronize the access to the watch variable.
This commit is contained in:
		
				
					committed by
					
						 Ignacio Casal Quinteiro
						Ignacio Casal Quinteiro
					
				
			
			
				
	
			
			
			
						parent
						
							9c7a57dcc5
						
					
				
				
					commit
					f45b5ea776
				
			| @@ -179,6 +179,10 @@ typedef struct { | ||||
|   CRITICAL_SECTION *cache_lock; | ||||
|   GNode *cache_root; | ||||
|  | ||||
|   /* A lock to protect access to the watch variable */ | ||||
|   CRITICAL_SECTION watch_lock; | ||||
|   /* Contains the state of the watching thread. Any access to this variable | ||||
|    * must be done while holding the watch_lock critical section. */ | ||||
|   WatchThreadState *watch; | ||||
| } GRegistrySettingsBackend; | ||||
|  | ||||
| @@ -1901,6 +1905,7 @@ watch_thread_function (LPVOID parameter) | ||||
|   return -1; | ||||
| } | ||||
|  | ||||
| /* This function assumes you hold the watch lock! */ | ||||
| static gboolean | ||||
| watch_start (GRegistrySettingsBackend *self) | ||||
| { | ||||
| @@ -1947,6 +1952,7 @@ fail: | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| /* This function assumes you hold the watch lock! */ | ||||
| /* This function assumes you hold the message lock! */ | ||||
| static void | ||||
| watch_stop_unlocked (GRegistrySettingsBackend *self) | ||||
| @@ -1982,6 +1988,7 @@ watch_stop_unlocked (GRegistrySettingsBackend *self) | ||||
|   self->watch = NULL; | ||||
| } | ||||
|  | ||||
| /* This function assumes you hold the watch lock! */ | ||||
| static gboolean | ||||
| watch_add_notify (GRegistrySettingsBackend *self, | ||||
|                   HANDLE                    event, | ||||
| @@ -2055,6 +2062,7 @@ watch_add_notify (GRegistrySettingsBackend *self, | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| /* This function assumes you hold the watch lock! */ | ||||
| static void | ||||
| watch_remove_notify (GRegistrySettingsBackend *self, | ||||
|                      const gchar              *key_name) | ||||
| @@ -2105,12 +2113,17 @@ g_registry_settings_backend_subscribe (GSettingsBackend *backend, | ||||
|   HANDLE event; | ||||
|   LONG result; | ||||
|  | ||||
|   EnterCriticalSection (&self->watch_lock); | ||||
|   if (self->watch == NULL && !watch_start (self)) | ||||
|     return; | ||||
|     { | ||||
|       LeaveCriticalSection (&self->watch_lock); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|   if (g_atomic_int_dec_and_test (&self->watch->watches_remaining)) | ||||
|     { | ||||
|       g_atomic_int_inc (&self->watch->watches_remaining); | ||||
|       LeaveCriticalSection (&self->watch_lock); | ||||
|       g_warning ("subscribe() failed: only %i different paths may be watched.", MAX_WATCHES); | ||||
|       return; | ||||
|     } | ||||
| @@ -2139,6 +2152,7 @@ g_registry_settings_backend_subscribe (GSettingsBackend *backend, | ||||
|     { | ||||
|       g_message_win32_error (result, "gregistrysettingsbackend: Unable to subscribe to key %s.", key_name); | ||||
|       g_atomic_int_inc (&self->watch->watches_remaining); | ||||
|       LeaveCriticalSection (&self->watch_lock); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
| @@ -2147,6 +2161,7 @@ g_registry_settings_backend_subscribe (GSettingsBackend *backend, | ||||
|     { | ||||
|       g_message_win32_error (result, "gregistrysettingsbackend: CreateEvent failed."); | ||||
|       g_atomic_int_inc (&self->watch->watches_remaining); | ||||
|       LeaveCriticalSection (&self->watch_lock); | ||||
|       RegCloseKey (hpath); | ||||
|       return; | ||||
|     } | ||||
| @@ -2159,15 +2174,21 @@ g_registry_settings_backend_subscribe (GSettingsBackend *backend, | ||||
|       RegCloseKey (hpath); | ||||
|       CloseHandle (event); | ||||
|     } | ||||
|  | ||||
|   LeaveCriticalSection (&self->watch_lock); | ||||
| } | ||||
|  | ||||
| static void | ||||
| g_registry_settings_backend_unsubscribe (GSettingsBackend *backend, | ||||
|                                          const char       *key_name) | ||||
| { | ||||
|   GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend); | ||||
|  | ||||
|   trace ("unsubscribe: %s.\n", key_name); | ||||
|  | ||||
|   watch_remove_notify (G_REGISTRY_SETTINGS_BACKEND (backend), key_name); | ||||
|   EnterCriticalSection (&self->watch_lock); | ||||
|   watch_remove_notify (self, key_name); | ||||
|   LeaveCriticalSection (&self->watch_lock); | ||||
| } | ||||
|  | ||||
| /******************************************************************************** | ||||
| @@ -2191,6 +2212,7 @@ g_registry_settings_backend_finalize (GObject *object) | ||||
|       EnterCriticalSection (self->watch->message_lock); | ||||
|       watch_stop_unlocked (self); | ||||
|     } | ||||
|   DeleteCriticalSection (&self->watch_lock); | ||||
|  | ||||
|   DeleteCriticalSection (self->cache_lock); | ||||
|   g_slice_free (CRITICAL_SECTION, self->cache_lock); | ||||
| @@ -2341,6 +2363,7 @@ g_registry_settings_backend_init (GRegistrySettingsBackend *self) | ||||
|   InitializeCriticalSection (self->cache_lock); | ||||
|  | ||||
|   self->watch = NULL; | ||||
|   InitializeCriticalSection (&self->watch_lock); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user