Be more strict and verbose while testing
[wine] / server / semaphore.c
1 /*
2  * Server-side semaphore management
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  *
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
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28
29 #include "windef.h"
30 #include "winternl.h"
31
32 #include "handle.h"
33 #include "thread.h"
34 #include "request.h"
35
36 struct semaphore
37 {
38     struct object  obj;    /* object header */
39     unsigned int   count;  /* current count */
40     unsigned int   max;    /* maximum possible count */
41 };
42
43 static void semaphore_dump( struct object *obj, int verbose );
44 static int semaphore_signaled( struct object *obj, struct thread *thread );
45 static int semaphore_satisfied( struct object *obj, struct thread *thread );
46 static int semaphore_signal( struct object *obj, unsigned int access );
47
48 static const struct object_ops semaphore_ops =
49 {
50     sizeof(struct semaphore),      /* size */
51     semaphore_dump,                /* dump */
52     add_queue,                     /* add_queue */
53     remove_queue,                  /* remove_queue */
54     semaphore_signaled,            /* signaled */
55     semaphore_satisfied,           /* satisfied */
56     semaphore_signal,              /* signal */
57     no_get_fd,                     /* get_fd */
58     no_lookup_name,                /* lookup_name */
59     no_close_handle,               /* close_handle */
60     no_destroy                     /* destroy */
61 };
62
63
64 static struct semaphore *create_semaphore( const struct unicode_str *name, unsigned int attr,
65                                            unsigned int initial, unsigned int max )
66 {
67     struct semaphore *sem;
68
69     if (!max || (initial > max))
70     {
71         set_error( STATUS_INVALID_PARAMETER );
72         return NULL;
73     }
74     if ((sem = create_named_object( sync_namespace, &semaphore_ops, name, attr )))
75     {
76         if (get_error() != STATUS_OBJECT_NAME_EXISTS)
77         {
78             /* initialize it if it didn't already exist */
79             sem->count = initial;
80             sem->max   = max;
81         }
82     }
83     return sem;
84 }
85
86 static int release_semaphore( struct semaphore *sem, unsigned int count,
87                               unsigned int *prev )
88 {
89     if (prev) *prev = sem->count;
90     if (sem->count + count < sem->count || sem->count + count > sem->max)
91     {
92         set_error( STATUS_SEMAPHORE_LIMIT_EXCEEDED );
93         return 0;
94     }
95     else if (sem->count)
96     {
97         /* there cannot be any thread to wake up if the count is != 0 */
98         sem->count += count;
99     }
100     else
101     {
102         sem->count = count;
103         wake_up( &sem->obj, count );
104     }
105     return 1;
106 }
107
108 static void semaphore_dump( struct object *obj, int verbose )
109 {
110     struct semaphore *sem = (struct semaphore *)obj;
111     assert( obj->ops == &semaphore_ops );
112     fprintf( stderr, "Semaphore count=%d max=%d ", sem->count, sem->max );
113     dump_object_name( &sem->obj );
114     fputc( '\n', stderr );
115 }
116
117 static int semaphore_signaled( struct object *obj, struct thread *thread )
118 {
119     struct semaphore *sem = (struct semaphore *)obj;
120     assert( obj->ops == &semaphore_ops );
121     return (sem->count > 0);
122 }
123
124 static int semaphore_satisfied( struct object *obj, struct thread *thread )
125 {
126     struct semaphore *sem = (struct semaphore *)obj;
127     assert( obj->ops == &semaphore_ops );
128     assert( sem->count );
129     sem->count--;
130     return 0;  /* not abandoned */
131 }
132
133 static int semaphore_signal( struct object *obj, unsigned int access )
134 {
135     struct semaphore *sem = (struct semaphore *)obj;
136     assert( obj->ops == &semaphore_ops );
137
138     if (!(access & SEMAPHORE_MODIFY_STATE))
139     {
140         set_error( STATUS_ACCESS_DENIED );
141         return 0;
142     }
143     return release_semaphore( sem, 1, NULL );
144 }
145
146 /* create a semaphore */
147 DECL_HANDLER(create_semaphore)
148 {
149     struct semaphore *sem;
150     struct unicode_str name;
151
152     reply->handle = 0;
153     get_req_unicode_str( &name );
154     if ((sem = create_semaphore( &name, req->attributes, req->initial, req->max )))
155     {
156         reply->handle = alloc_handle( current->process, sem, req->access,
157                                       req->attributes & OBJ_INHERIT );
158         release_object( sem );
159     }
160 }
161
162 /* open a handle to a semaphore */
163 DECL_HANDLER(open_semaphore)
164 {
165     struct unicode_str name;
166
167     get_req_unicode_str( &name );
168     reply->handle = open_object( sync_namespace, &name, &semaphore_ops, req->access, req->attributes );
169 }
170
171 /* release a semaphore */
172 DECL_HANDLER(release_semaphore)
173 {
174     struct semaphore *sem;
175
176     if ((sem = (struct semaphore *)get_handle_obj( current->process, req->handle,
177                                                    SEMAPHORE_MODIFY_STATE, &semaphore_ops )))
178     {
179         release_semaphore( sem, req->count, &reply->prev_count );
180         release_object( sem );
181     }
182 }