1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 #include <kproc/extern.h>
27 #include <kproc/cond.h>
28 #include <klib/rc.h>
29 #include <sysalloc.h>
30 #include <atomic32.h>
31 
32 #include <stdlib.h>
33 
34 
35 /*--------------------------------------------------------------------------
36  * KCondition
37  *  a POSIX-style condition object
38  */
39 struct KCondition
40 {
41     atomic32_t refcount;
42 };
43 
44 
45 /* Whack
46  */
47 static
KConditionWhack(KCondition * self)48 rc_t KConditionWhack ( KCondition *self )
49 {
50     free ( self );
51     return 0;
52 }
53 
54 
55 /* Make
56  *  create a condition
57  */
KConditionMake(KCondition ** condp)58 LIB_EXPORT rc_t CC KConditionMake ( KCondition **condp )
59 {
60     rc_t rc;
61     if ( condp == NULL )
62         rc = RC ( rcPS, rcCondition, rcConstructing, rcParam, rcNull );
63     else
64     {
65         KCondition *cond = malloc ( sizeof * cond );
66         if ( cond == NULL )
67             rc = RC ( rcPS, rcCondition, rcConstructing, rcMemory, rcExhausted );
68         else
69         {
70             atomic32_set ( & cond -> refcount, 1 );
71             * condp = cond;
72             return 0;
73         }
74 
75         * condp = NULL;
76     }
77     return rc;
78 }
79 
80 
81 /* AddRef
82  * Release
83  */
KConditionAddRef(const KCondition * cself)84 LIB_EXPORT rc_t CC KConditionAddRef ( const KCondition *cself )
85 {
86     if ( cself != NULL )
87         atomic32_inc ( & ( ( KCondition* ) cself ) -> refcount );
88     return 0;
89 }
90 
KConditionRelease(const KCondition * cself)91 LIB_EXPORT rc_t CC KConditionRelease ( const KCondition *cself )
92 {
93     KCondition *self = ( KCondition* ) cself;
94     if ( cself != NULL )
95     {
96         if ( atomic32_dec_and_test ( & self -> refcount ) )
97             return KConditionWhack ( self );
98     }
99     return 0;
100 }
101 
102 
103 /* Wait
104  *  block on external lock until signaled
105  */
KConditionWait(KCondition * self,struct KLock * lock)106 LIB_EXPORT rc_t CC KConditionWait ( KCondition *self, struct KLock *lock )
107 {
108     if ( self == NULL )
109         return RC ( rcPS, rcCondition, rcWaiting, rcSelf, rcNull );
110     if ( lock == NULL )
111         return RC ( rcPS, rcCondition, rcWaiting, rcLock, rcNull );
112 
113     return RC ( rcPS, rcCondition, rcWaiting, rcThread, rcDeadlock );
114 }
115 
KConditionTimedWait(KCondition * self,struct KLock * lock,struct timeout_t * tm)116 LIB_EXPORT rc_t CC KConditionTimedWait ( KCondition *self, struct KLock *lock, struct timeout_t *tm )
117 {
118     if ( self == NULL )
119         return RC ( rcPS, rcCondition, rcWaiting, rcSelf, rcNull );
120     if ( lock == NULL )
121         return RC ( rcPS, rcCondition, rcWaiting, rcLock, rcNull );
122     if ( tm == NULL )
123         return RC ( rcPS, rcCondition, rcWaiting, rcTimeout, rcNull );
124 
125     return RC ( rcPS, rcCondition, rcWaiting, rcThread, rcDeadlock );
126 }
127 
128 
129 /* Signal
130  *  signal waiting threads
131  *  awaken at most a single thread
132  */
KConditionSignal(KCondition * self)133 LIB_EXPORT rc_t CC KConditionSignal ( KCondition *self )
134 {
135     if ( self == NULL )
136         return RC ( rcPS, rcCondition, rcSignaling, rcSelf, rcNull );
137 
138     return RC ( rcPS, rcCondition, rcSignaling, rcThread, rcDeadlock );
139 }
140 
141 
142 /* Broadcast
143  *  signal waiting threads
144  *  awaken all waiting thread
145  */
KConditionBroadcast(KCondition * self)146 LIB_EXPORT rc_t CC KConditionBroadcast ( KCondition *self )
147 {
148     if ( self == NULL )
149         return RC ( rcPS, rcCondition, rcSignaling, rcSelf, rcNull );
150 
151     return RC ( rcPS, rcCondition, rcSignaling, rcThread, rcDeadlock );
152 }
153