From: Rémi Bernon rbernon@codeweavers.com
--- server/semaphore.c | 172 +++++++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 51 deletions(-)
diff --git a/server/semaphore.c b/server/semaphore.c index 304a821bcec..4b31bfe806c 100644 --- a/server/semaphore.c +++ b/server/semaphore.c @@ -50,30 +50,119 @@ struct type_descr semaphore_type = }, };
+struct semaphore_sync +{ + struct object obj; /* object header */ + unsigned int count; /* current count */ + unsigned int max; /* maximum possible count */ +}; + +static void semaphore_sync_dump( struct object *obj, int verbose ); +static int semaphore_sync_signaled( struct object *obj, struct wait_queue_entry *entry ); +static void semaphore_sync_satisfied( struct object *obj, struct wait_queue_entry *entry ); + +static const struct object_ops semaphore_sync_ops = +{ + sizeof(struct semaphore_sync), /* size */ + &no_type, /* type */ + semaphore_sync_dump, /* dump */ + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + semaphore_sync_signaled, /* signaled */ + semaphore_sync_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_get_sync, /* get_sync */ + default_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ + no_lookup_name, /* lookup_name */ + directory_link_name, /* link_name */ + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ +}; + +static int release_semaphore( struct semaphore_sync *sem, unsigned int count, + unsigned int *prev ) +{ + if (prev) *prev = sem->count; + if (sem->count + count < sem->count || sem->count + count > sem->max) + { + set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED ); + return 0; + } + else if (sem->count) + { + /* there cannot be any thread to wake up if the count is != 0 */ + sem->count += count; + } + else + { + sem->count = count; + wake_up( &sem->obj, count ); + } + return 1; +} + +static void semaphore_sync_dump( struct object *obj, int verbose ) +{ + struct semaphore_sync *sem = (struct semaphore_sync *)obj; + assert( obj->ops == &semaphore_sync_ops ); + fprintf( stderr, "Semaphore count=%d max=%d\n", sem->count, sem->max ); +} + +static int semaphore_sync_signaled( struct object *obj, struct wait_queue_entry *entry ) +{ + struct semaphore_sync *sem = (struct semaphore_sync *)obj; + assert( obj->ops == &semaphore_sync_ops ); + return (sem->count > 0); +} + +static void semaphore_sync_satisfied( struct object *obj, struct wait_queue_entry *entry ) +{ + struct semaphore_sync *sem = (struct semaphore_sync *)obj; + assert( obj->ops == &semaphore_sync_ops ); + assert( sem->count ); + sem->count--; +} + +static struct semaphore_sync *create_semaphore_sync( unsigned int initial, unsigned int max ) +{ + struct semaphore_sync *sem; + + if (!(sem = alloc_object( &semaphore_sync_ops ))) return NULL; + sem->count = initial; + sem->max = max; + return sem; +} + struct semaphore { - struct object obj; /* object header */ - unsigned int count; /* current count */ - unsigned int max; /* maximum possible count */ + struct object obj; /* object header */ + struct semaphore_sync *sync; /* semaphore sync object */ };
static void semaphore_dump( struct object *obj, int verbose ); -static int semaphore_signaled( struct object *obj, struct wait_queue_entry *entry ); -static void semaphore_satisfied( struct object *obj, struct wait_queue_entry *entry ); +static struct object *semaphore_get_sync( struct object *obj ); static int semaphore_signal( struct object *obj, unsigned int access ); +static void semaphore_destroy( struct object *obj );
static const struct object_ops semaphore_ops = { sizeof(struct semaphore), /* size */ &semaphore_type, /* type */ semaphore_dump, /* dump */ - add_queue, /* add_queue */ - remove_queue, /* remove_queue */ - semaphore_signaled, /* signaled */ - semaphore_satisfied, /* satisfied */ + NULL, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* satisfied */ semaphore_signal, /* signal */ no_get_fd, /* get_fd */ - default_get_sync, /* get_sync */ + semaphore_get_sync, /* get_sync */ default_map_access, /* map_access */ default_get_sd, /* get_sd */ default_set_sd, /* set_sd */ @@ -84,10 +173,9 @@ static const struct object_ops semaphore_ops = no_open_file, /* open_file */ no_kernel_obj_list, /* get_kernel_obj_list */ no_close_handle, /* close_handle */ - no_destroy /* destroy */ + semaphore_destroy, /* destroy */ };
- static struct semaphore *create_semaphore( struct object *root, const struct unicode_str *name, unsigned int attr, unsigned int initial, unsigned int max, const struct security_descriptor *sd ) @@ -104,55 +192,30 @@ static struct semaphore *create_semaphore( struct object *root, const struct uni if (get_error() != STATUS_OBJECT_NAME_EXISTS) { /* initialize it if it didn't already exist */ - sem->count = initial; - sem->max = max; + sem->sync = NULL; + + if (!(sem->sync = create_semaphore_sync( initial, max ))) + { + release_object( sem ); + return NULL; + } } } return sem; }
-static int release_semaphore( struct semaphore *sem, unsigned int count, - unsigned int *prev ) -{ - if (prev) *prev = sem->count; - if (sem->count + count < sem->count || sem->count + count > sem->max) - { - set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED ); - return 0; - } - else if (sem->count) - { - /* there cannot be any thread to wake up if the count is != 0 */ - sem->count += count; - } - else - { - sem->count = count; - wake_up( &sem->obj, count ); - } - return 1; -} - static void semaphore_dump( struct object *obj, int verbose ) { struct semaphore *sem = (struct semaphore *)obj; assert( obj->ops == &semaphore_ops ); - fprintf( stderr, "Semaphore count=%d max=%d\n", sem->count, sem->max ); + sem->sync->obj.ops->dump( &sem->sync->obj, verbose ); }
-static int semaphore_signaled( struct object *obj, struct wait_queue_entry *entry ) +static struct object *semaphore_get_sync( struct object *obj ) { struct semaphore *sem = (struct semaphore *)obj; assert( obj->ops == &semaphore_ops ); - return (sem->count > 0); -} - -static void semaphore_satisfied( struct object *obj, struct wait_queue_entry *entry ) -{ - struct semaphore *sem = (struct semaphore *)obj; - assert( obj->ops == &semaphore_ops ); - assert( sem->count ); - sem->count--; + return grab_object( sem->sync ); }
static int semaphore_signal( struct object *obj, unsigned int access ) @@ -165,7 +228,14 @@ static int semaphore_signal( struct object *obj, unsigned int access ) set_error( STATUS_ACCESS_DENIED ); return 0; } - return release_semaphore( sem, 1, NULL ); + return release_semaphore( sem->sync, 1, NULL ); +} + +static void semaphore_destroy( struct object *obj ) +{ + struct semaphore *sem = (struct semaphore *)obj; + assert( obj->ops == &semaphore_ops ); + if (sem->sync) release_object( sem->sync ); }
/* create a semaphore */ @@ -209,7 +279,7 @@ DECL_HANDLER(release_semaphore) if ((sem = (struct semaphore *)get_handle_obj( current->process, req->handle, SEMAPHORE_MODIFY_STATE, &semaphore_ops ))) { - release_semaphore( sem, req->count, &reply->prev_count ); + release_semaphore( sem->sync, req->count, &reply->prev_count ); release_object( sem ); } } @@ -222,8 +292,8 @@ DECL_HANDLER(query_semaphore) if ((sem = (struct semaphore *)get_handle_obj( current->process, req->handle, SEMAPHORE_QUERY_STATE, &semaphore_ops ))) { - reply->current = sem->count; - reply->max = sem->max; + reply->current = sem->sync->count; + reply->max = sem->sync->max; release_object( sem ); } }