blob: 6cc1012a0351004d452545ca91f0ab07b6ac5b11 [file] [log] [blame]
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001/*
2 * Server-side semaphore management
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000019 */
20
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000021#include "config.h"
22#include "wine/port.h"
23
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000024#include <assert.h>
25#include <stdio.h>
26#include <stdlib.h>
Robert Lunnon95414ef2005-11-22 12:01:05 +000027#include <stdarg.h>
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000028
Ge van Geldorp1a1583a2005-11-28 17:32:54 +010029#include "ntstatus.h"
30#define WIN32_NO_STATUS
Alexandre Julliard435e2e62002-12-10 22:56:43 +000031#include "windef.h"
Vitaliy Margolena9960002005-10-27 18:30:37 +000032#include "winternl.h"
Alexandre Julliard43c190e1999-05-15 10:48:19 +000033
34#include "handle.h"
35#include "thread.h"
Alexandre Julliard5bc78081999-06-22 17:26:53 +000036#include "request.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000037
38struct semaphore
39{
40 struct object obj; /* object header */
41 unsigned int count; /* current count */
42 unsigned int max; /* maximum possible count */
43};
44
Alexandre Julliard338e7571998-12-27 15:28:54 +000045static void semaphore_dump( struct object *obj, int verbose );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000046static int semaphore_signaled( struct object *obj, struct thread *thread );
47static int semaphore_satisfied( struct object *obj, struct thread *thread );
Mike McCormackf92fff62005-04-24 17:35:52 +000048static int semaphore_signal( struct object *obj, unsigned int access );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000049
50static const struct object_ops semaphore_ops =
51{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000052 sizeof(struct semaphore), /* size */
53 semaphore_dump, /* dump */
54 add_queue, /* add_queue */
55 remove_queue, /* remove_queue */
56 semaphore_signaled, /* signaled */
57 semaphore_satisfied, /* satisfied */
Mike McCormackf92fff62005-04-24 17:35:52 +000058 semaphore_signal, /* signal */
Alexandre Julliard1ab243b2000-12-19 02:12:45 +000059 no_get_fd, /* get_fd */
Alexandre Julliard28beba32005-12-12 14:57:40 +010060 no_map_access, /* map_access */
Vitaliy Margolenbaffcb92005-11-22 14:55:42 +000061 no_lookup_name, /* lookup_name */
Alexandre Julliardb9b1ea92005-06-09 15:39:52 +000062 no_close_handle, /* close_handle */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000063 no_destroy /* destroy */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000064};
65
66
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +010067static struct semaphore *create_semaphore( struct directory *root, const struct unicode_str *name,
68 unsigned int attr, unsigned int initial, unsigned int max )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000069{
70 struct semaphore *sem;
71
72 if (!max || (initial > max))
73 {
Alexandre Julliardcb1fc732000-01-24 21:58:06 +000074 set_error( STATUS_INVALID_PARAMETER );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000075 return NULL;
76 }
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +010077 if ((sem = create_named_object_dir( root, name, attr, &semaphore_ops )))
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000078 {
Vitaliy Margolen893987b2005-11-21 16:27:03 +000079 if (get_error() != STATUS_OBJECT_NAME_EXISTS)
Alexandre Julliard5bc78081999-06-22 17:26:53 +000080 {
81 /* initialize it if it didn't already exist */
82 sem->count = initial;
83 sem->max = max;
84 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000085 }
Alexandre Julliard5bc78081999-06-22 17:26:53 +000086 return sem;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000087}
88
Mike McCormackf92fff62005-04-24 17:35:52 +000089static int release_semaphore( struct semaphore *sem, unsigned int count,
90 unsigned int *prev )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000091{
Mike McCormackf92fff62005-04-24 17:35:52 +000092 if (prev) *prev = sem->count;
93 if (sem->count + count < sem->count || sem->count + count > sem->max)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000094 {
Mike McCormackf92fff62005-04-24 17:35:52 +000095 set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED );
96 return 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000097 }
Mike McCormackf92fff62005-04-24 17:35:52 +000098 else if (sem->count)
99 {
100 /* there cannot be any thread to wake up if the count is != 0 */
101 sem->count += count;
102 }
103 else
104 {
105 sem->count = count;
106 wake_up( &sem->obj, count );
107 }
108 return 1;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000109}
110
Alexandre Julliard338e7571998-12-27 15:28:54 +0000111static void semaphore_dump( struct object *obj, int verbose )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000112{
113 struct semaphore *sem = (struct semaphore *)obj;
114 assert( obj->ops == &semaphore_ops );
Alexandre Julliardd16319c1999-11-25 21:30:24 +0000115 fprintf( stderr, "Semaphore count=%d max=%d ", sem->count, sem->max );
116 dump_object_name( &sem->obj );
117 fputc( '\n', stderr );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000118}
119
120static int semaphore_signaled( struct object *obj, struct thread *thread )
121{
122 struct semaphore *sem = (struct semaphore *)obj;
123 assert( obj->ops == &semaphore_ops );
124 return (sem->count > 0);
125}
126
127static int semaphore_satisfied( struct object *obj, struct thread *thread )
128{
129 struct semaphore *sem = (struct semaphore *)obj;
130 assert( obj->ops == &semaphore_ops );
131 assert( sem->count );
132 sem->count--;
133 return 0; /* not abandoned */
134}
135
Mike McCormackf92fff62005-04-24 17:35:52 +0000136static int semaphore_signal( struct object *obj, unsigned int access )
137{
138 struct semaphore *sem = (struct semaphore *)obj;
139 assert( obj->ops == &semaphore_ops );
140
141 if (!(access & SEMAPHORE_MODIFY_STATE))
142 {
143 set_error( STATUS_ACCESS_DENIED );
144 return 0;
145 }
146 return release_semaphore( sem, 1, NULL );
147}
148
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000149/* create a semaphore */
150DECL_HANDLER(create_semaphore)
151{
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000152 struct semaphore *sem;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000153 struct unicode_str name;
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +0100154 struct directory *root = NULL;
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000155
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000156 reply->handle = 0;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000157 get_req_unicode_str( &name );
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +0100158 if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
159 return;
160
161 if ((sem = create_semaphore( root, &name, req->attributes, req->initial, req->max )))
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000162 {
Alexandre Julliard24560e72005-12-09 13:58:25 +0100163 reply->handle = alloc_handle( current->process, sem, req->access, req->attributes );
Alexandre Julliard5bc78081999-06-22 17:26:53 +0000164 release_object( sem );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000165 }
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +0100166
167 if (root) release_object( root );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000168}
169
170/* open a handle to a semaphore */
171DECL_HANDLER(open_semaphore)
172{
Alexandre Julliardead9b062005-11-18 16:31:18 +0000173 struct unicode_str name;
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +0100174 struct directory *root = NULL;
Alexandre Julliard3764da62005-12-05 12:52:05 +0100175 struct semaphore *sem;
Alexandre Julliardead9b062005-11-18 16:31:18 +0000176
177 get_req_unicode_str( &name );
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +0100178 if (req->rootdir && !(root = get_directory_obj( current->process, req->rootdir, 0 )))
179 return;
180
Alexandre Julliard3764da62005-12-05 12:52:05 +0100181 if ((sem = open_object_dir( root, &name, req->attributes, &semaphore_ops )))
182 {
Alexandre Julliard24560e72005-12-09 13:58:25 +0100183 reply->handle = alloc_handle( current->process, &sem->obj, req->access, req->attributes );
Alexandre Julliard3764da62005-12-05 12:52:05 +0100184 release_object( sem );
185 }
Vitaliy Margolen5daae3d2005-12-02 16:01:17 +0100186
187 if (root) release_object( root );
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000188}
189
190/* release a semaphore */
191DECL_HANDLER(release_semaphore)
192{
Mike McCormackf92fff62005-04-24 17:35:52 +0000193 struct semaphore *sem;
194
195 if ((sem = (struct semaphore *)get_handle_obj( current->process, req->handle,
196 SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
197 {
198 release_semaphore( sem, req->count, &reply->prev_count );
199 release_object( sem );
200 }
Alexandre Julliard43c190e1999-05-15 10:48:19 +0000201}