[DAPL2] sync with WinOF 2.1 branch
[mirror/winof/.git] / inc / complib / cl_passivelock.h
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 /*\r
35  * Abstract:\r
36  *      This file contains the passive lock, which synchronizes passive threads.\r
37  *      The passive lock allows multiple readers to access a resource\r
38  *      simultaneously, exclusive from a single thread writting.  It is similar\r
39  *      in behavior to the passive lock, but works at passive only.\r
40  *\r
41  * Environment:\r
42  *      All\r
43  */\r
44 \r
45 \r
46 #ifndef _CL_PASSIVE_LOCK_H_\r
47 #define _CL_PASSIVE_LOCK_H_\r
48 \r
49 \r
50 #include <complib/cl_event.h>\r
51 #include <complib/cl_atomic.h>\r
52 \r
53 \r
54 /****h* Component Library/Passive Lock\r
55 * NAME\r
56 *       Passive Lock\r
57 *\r
58 * DESCRIPTION\r
59 *       The Passive Lock provides synchronization between multiple threads that\r
60 *       are sharing the lock with a single thread holding the lock exclusively.\r
61 *\r
62 *       Passive lock works exclusively between threads and cannot be used in\r
63 *       situations where the caller cannot be put into a waiting state.\r
64 *\r
65 *       The passive lock functions operate a cl_plock_t structure which should\r
66 *       be treated as opaque and should be manipulated only through the provided\r
67 *       functions.\r
68 *\r
69 * SEE ALSO\r
70 *       Structures:\r
71 *               cl_plock_t\r
72 *\r
73 *       Initialization:\r
74 *               cl_plock_construct, cl_plock_init, cl_plock_destroy\r
75 *\r
76 *       Manipulation\r
77 *               cl_plock_acquire, cl_plock_excl_acquire, cl_plock_release\r
78 *********/\r
79 \r
80 \r
81 /****s* Component Library: Passive Lock/cl_plock_t\r
82 * NAME\r
83 *       cl_plock_t\r
84 *\r
85 * DESCRIPTION\r
86 *       Passive Lock structure.\r
87 *\r
88 *       The cl_plock_t structure should be treated as opaque and should\r
89 *       be manipulated only through the provided functions.\r
90 *\r
91 * SYNOPSIS\r
92 */\r
93 typedef struct _cl_plock\r
94 {\r
95         cl_event_t              reader_event;\r
96         cl_event_t              writer_event;\r
97         atomic32_t              reader_count;\r
98 \r
99 } cl_plock_t;\r
100 /*\r
101 * FIELDS\r
102 *       reader_event\r
103 *               Event used to synchronize shared access to the lock.\r
104 *\r
105 *       writer_event\r
106 *               Event used to synchronize exclusive access to the lock.\r
107 *\r
108 *       reader_count\r
109 *               Number of threads holding the lock for shared access.\r
110 *\r
111 * SEE ALSO\r
112 *       Passive Lock\r
113 *********/\r
114 \r
115 \r
116 /****f* Component Library: Passive Lock/cl_plock_construct\r
117 * NAME\r
118 *       cl_plock_construct\r
119 *\r
120 * DESCRIPTION\r
121 *       The cl_plock_construct function initializes the state of a\r
122 *       passive lock.\r
123 *\r
124 * SYNOPSIS\r
125 */\r
126 CL_INLINE void CL_API\r
127 cl_plock_construct(\r
128         IN      cl_plock_t* const       p_lock )\r
129 {\r
130         CL_ASSERT( p_lock );\r
131 \r
132         p_lock->reader_count = 0;\r
133         cl_event_construct( &p_lock->reader_event );\r
134         cl_event_construct( &p_lock->writer_event );\r
135 }\r
136 /*\r
137 * PARAMETERS\r
138 *       p_lock\r
139 *               [in] Pointer to a cl_plock_t structure whose state to initialize.\r
140 *\r
141 * RETURN VALUE\r
142 *       This function does not return a value.\r
143 *\r
144 * NOTES\r
145 *       Allows calling cl_plock_destroy without first calling cl_plock_init.\r
146 *\r
147 *       Calling cl_plock_construct is a prerequisite to calling any other\r
148 *       passive lock function except cl_plock_init.\r
149 *\r
150 * SEE ALSO\r
151 *       Passive Lock, cl_plock_init, cl_plock_destroy\r
152 *********/\r
153 \r
154 \r
155 /****f* Component Library: Passive Lock/cl_plock_destroy\r
156 * NAME\r
157 *       cl_plock_destroy\r
158 *\r
159 * DESCRIPTION\r
160 *       The cl_plock_destroy function performs any necessary cleanup\r
161 *       of a passive lock.\r
162 *\r
163 * SYNOPSIS\r
164 */\r
165 CL_INLINE void CL_API\r
166 cl_plock_destroy(\r
167         IN      cl_plock_t* const       p_lock )\r
168 {\r
169         CL_ASSERT( p_lock );\r
170         CL_ASSERT( p_lock->reader_count == 0 );\r
171 \r
172         cl_event_destroy( &p_lock->writer_event );\r
173         cl_event_destroy( &p_lock->reader_event );\r
174 }\r
175 /*\r
176 * PARAMETERS\r
177 *       p_lock\r
178 *               [in] Pointer to a cl_plock_t structure whose state to initialize.\r
179 *\r
180 * RETURN VALUE\r
181 *       This function does not return a value.\r
182 *\r
183 * NOTES\r
184 *       cl_plock_destroy performs any necessary cleanup of the specified\r
185 *       passive lock.\r
186 *\r
187 *       This function must only be called if cl_plock_construct or\r
188 *       cl_plock_init has been called. The passive lock must not be held\r
189 *       when calling this function.\r
190 *\r
191 * SEE ALSO\r
192 *       Passive Lock, cl_plock_construct, cl_plock_init\r
193 *********/\r
194 \r
195 \r
196 /****f* Component Library: Passive Lock/cl_plock_init\r
197 * NAME\r
198 *       cl_plock_init\r
199 *\r
200 * DESCRIPTION\r
201 *       The cl_plock_init function initializes a passive lock.\r
202 *\r
203 * SYNOPSIS\r
204 */\r
205 CL_INLINE cl_status_t CL_API\r
206 cl_plock_init(\r
207         IN      cl_plock_t* const       p_lock )\r
208 {\r
209         cl_status_t     status;\r
210 \r
211         CL_ASSERT( p_lock );\r
212 \r
213         cl_plock_construct( p_lock );\r
214 \r
215         status = cl_event_init( &p_lock->writer_event, FALSE );\r
216         if( status != CL_SUCCESS )\r
217         {\r
218                 cl_plock_destroy( p_lock );\r
219                 return( status );\r
220         }\r
221 \r
222         status = cl_event_init( &p_lock->reader_event, FALSE );\r
223         if( status != CL_SUCCESS )\r
224         {\r
225                 cl_plock_destroy( p_lock );\r
226                 return( status );\r
227         }\r
228 \r
229         /*\r
230          * Set the writer event to signalled so that the first\r
231          * wait operation succeeds.\r
232          */\r
233         status = cl_event_signal( &p_lock->writer_event );\r
234         if( status != CL_SUCCESS )\r
235         {\r
236                 cl_plock_destroy( p_lock );\r
237                 return( status );\r
238         }\r
239 \r
240         /*\r
241          * Set the reader event to signalled so that the first\r
242          * wait operation succeeds.\r
243          */\r
244         status = cl_event_signal( &p_lock->reader_event );\r
245         if( status != CL_SUCCESS )\r
246         {\r
247                 cl_plock_destroy( p_lock );\r
248                 return( status );\r
249         }\r
250 \r
251         return( CL_SUCCESS );\r
252 }\r
253 /*\r
254 * PARAMETERS\r
255 *       p_lock\r
256 *               [in] Pointer to a cl_plock_t structure to initialize.\r
257 *\r
258 * RETURN VALUES\r
259 *       CL_SUCCESS if the passive lock was initialized successfully.\r
260 *\r
261 *       CL_ERROR otherwise.\r
262 *\r
263 * NOTES\r
264 *       Allows calling cl_plock_acquire, cl_plock_release,\r
265 *       cl_plock_excl_acquire, and cl_plock_excl_release.\r
266 *\r
267 * SEE ALSO\r
268 *       Passive Lock, cl_plock_construct, cl_plock_destroy,\r
269 *       cl_plock_excl_acquire, cl_plock_excl_release,\r
270 *       cl_plock_acquire, cl_plock_release\r
271 *********/\r
272 \r
273 \r
274 /****f* Component Library: Passive Lock/cl_plock_acquire\r
275 * NAME\r
276 *       cl_plock_acquire\r
277 *\r
278 * DESCRIPTION\r
279 *       The cl_plock_acquire function acquires a passive lock for\r
280 *       shared access.\r
281 *\r
282 * SYNOPSIS\r
283 */\r
284 CL_INLINE void CL_API\r
285 cl_plock_acquire(\r
286         IN      cl_plock_t* const       p_lock )\r
287 {\r
288         cl_status_t     status;\r
289 \r
290         CL_ASSERT( p_lock );\r
291 \r
292         status =\r
293                 cl_event_wait_on( &p_lock->reader_event, EVENT_NO_TIMEOUT, FALSE );\r
294         CL_ASSERT( status == CL_SUCCESS );\r
295 \r
296         /*\r
297          * Increment the reader count to block a thread trying for exclusive\r
298          * access.\r
299          */\r
300         cl_atomic_inc( &p_lock->reader_count );\r
301 #ifdef DBG_PASSIVE_LOCKS\r
302         cl_dbg_out( "cl_plock_acquire: ReaderCount = %u\n",\r
303                 p_lock->reader_count );\r
304 #endif\r
305         /*\r
306          * Release the reader event to satisfy the wait of another reader\r
307          * or a writer.\r
308          */\r
309         cl_event_signal( &p_lock->reader_event );\r
310 }\r
311 /*\r
312 * PARAMETERS\r
313 *       p_lock\r
314 *               [in] Pointer to a cl_plock_t structure to acquire.\r
315 *\r
316 * RETURN VALUE\r
317 *       This function does not return a value.\r
318 *\r
319 * SEE ALSO\r
320 *       Passive Lock, cl_plock_release, cl_plock_excl_acquire\r
321 *********/\r
322 \r
323 \r
324 /****f* Component Library: Passive Lock/cl_plock_excl_acquire\r
325 * NAME\r
326 *       cl_plock_excl_acquire\r
327 *\r
328 * DESCRIPTION\r
329 *       The cl_plock_excl_acquire function acquires exclusive access\r
330 *       to a passive lock.\r
331 *\r
332 * SYNOPSIS\r
333 */\r
334 CL_INLINE void CL_API\r
335 cl_plock_excl_acquire(\r
336         IN      cl_plock_t* const       p_lock )\r
337 {\r
338         cl_status_t     status;\r
339 \r
340         CL_ASSERT( p_lock );\r
341 \r
342         /* Acquire the reader event.  This will block new readers. */\r
343         status =\r
344                 cl_event_wait_on( &p_lock->reader_event, EVENT_NO_TIMEOUT, FALSE );\r
345         CL_ASSERT( status == CL_SUCCESS );\r
346 \r
347         /* Wait for the writer event until all readers have exited. */\r
348         while( p_lock->reader_count )\r
349         {\r
350 #ifdef DBG_PASSIVE_LOCKS\r
351                 cl_dbg_out( "cl_plock_excl_acquire: ReaderCount = %u\n",\r
352                         p_lock->reader_count );\r
353 #endif\r
354                 status =\r
355                         cl_event_wait_on( &p_lock->writer_event, EVENT_NO_TIMEOUT, FALSE );\r
356                 CL_ASSERT( status == CL_SUCCESS );\r
357         }\r
358 \r
359 #ifdef DBG_PASSIVE_LOCKS\r
360         cl_dbg_out( "cl_plock_excl_acquire: Exit\n" );\r
361 #endif\r
362 }\r
363 /*\r
364 * PARAMETERS\r
365 *       p_lock\r
366 *               [in] Pointer to a cl_plock_t structure to acquire exclusively.\r
367 *\r
368 * RETURN VALUE\r
369 *       This function does not return a value.\r
370 *\r
371 * SEE ALSO\r
372 *       Passive Lock, cl_plock_release, cl_plock_acquire\r
373 *********/\r
374 \r
375 \r
376 /****f* Component Library: Passive Lock/cl_plock_release\r
377 * NAME\r
378 *       cl_plock_release\r
379 *\r
380 * DESCRIPTION\r
381 *       The cl_plock_release function releases a passive lock from\r
382 *       shared or exclusive access.\r
383 *\r
384 * SYNOPSIS\r
385 */\r
386 CL_INLINE void CL_API\r
387 cl_plock_release(\r
388         IN      cl_plock_t* const       p_lock )\r
389 {\r
390         CL_ASSERT( p_lock );\r
391 \r
392         if( p_lock->reader_count )\r
393         {\r
394 \r
395                 /*\r
396                  * Decrement the count to allow a thread waiting for exclusive\r
397                  * access to continue.\r
398                  */\r
399                 cl_atomic_dec( &p_lock->reader_count );\r
400 \r
401                 #ifdef DBG_PASSIVE_LOCKS\r
402                         cl_dbg_out( "cl_plock_release: ReaderCount = %u\n",\r
403                                 p_lock->reader_count );\r
404                 #endif\r
405 \r
406                 /* Release a writer, if any. */\r
407                 cl_event_signal( &p_lock->writer_event );\r
408         }\r
409         else\r
410         {\r
411                 /* Release threads waiting to acquire the lock. */\r
412                 cl_event_signal( &p_lock->reader_event );\r
413                 cl_event_signal( &p_lock->writer_event );\r
414 \r
415                 #ifdef DBG_PASSIVE_LOCKS\r
416                         cl_dbg_out( "cl_plock_release: Exit\n" );\r
417                 #endif\r
418         }\r
419 }\r
420 /*\r
421 * PARAMETERS\r
422 *       p_lock\r
423 *               [in] Pointer to a cl_plock_t structure to release.\r
424 *\r
425 * RETURN VALUE\r
426 *       This function does not return a value.\r
427 *\r
428 * SEE ALSO\r
429 *       Passive Lock, cl_plock_acquire, cl_plock_excl_acquire\r
430 *********/\r
431 \r
432 \r
433 #endif /* _CL_PASSIVE_LOCK_H_ */\r