correct comment
[AROS.git] / rom / exec / releasesemaphore.c
blob262844aa432a36f9c539da0a7b5c423d52abfdb0
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Release a semaphore.
6 Lang: english
7 */
9 #include <exec/semaphores.h>
10 #include <proto/exec.h>
12 #include "exec_intern.h"
13 #include "exec_util.h"
14 #include "semaphores.h"
16 #define CHECK_TASK 0 /* it seems to be legal to call ObtainSemaphore in one task and ReleaseSemaphore in another */
18 /*****************************************************************************/
19 #undef Exec
20 #ifdef UseExecstubs
21 # define Exec _Exec
22 #endif
24 /* NAME */
25 #include <proto/exec.h>
27 AROS_LH1(void, ReleaseSemaphore,
29 /* SYNOPSIS */
30 AROS_LHA(struct SignalSemaphore *, sigSem, A0),
32 /* LOCATION */
33 struct ExecBase *, SysBase, 95, Exec)
35 /* FUNCTION
36 Releases a lock on a semaphore obtained with either ObtainSemaphore(),
37 ObtainSemaphoreShared(), AttemptSemaphore or AttemptSemaphoreShared().
38 Each call to one of those functions must be accompanied by one call
39 to ReleaseSemaphore().
41 INPUTS
42 sigSem - pointer to semaphore structure
44 RESULT
46 NOTES
47 This function preserves all registers.
49 EXAMPLE
51 BUGS
53 SEE ALSO
55 INTERNALS
57 *****************************************************************************/
59 #undef Exec
61 AROS_LIBFUNC_INIT
63 struct TraceLocation tp = CURRENT_LOCATION("ReleaseSemaphore");
64 struct Task *me = FindTask(NULL);
66 /* We can be called from within exec's pre-init code. It's okay. */
67 if (!me)
68 return;
70 if (me->tc_State == TS_REMOVED)
71 return;
73 if (!CheckSemaphore(sigSem, &tp, SysBase))
74 return;
76 /* Protect the semaphore structure from multiple access. */
77 Forbid();
79 /* Release one on the nest count */
80 sigSem->ss_NestCount--;
81 sigSem->ss_QueueCount--;
83 if(sigSem->ss_NestCount == 0)
86 There are two cases here. Either we are a shared
87 semaphore, or not. If we are not, make sure that the
88 correct Task is calling ReleaseSemaphore()
91 #if CHECK_TASK
92 if (sigSem->ss_Owner != NULL && sigSem->ss_Owner != me)
95 If it is not, there is a chance that the semaphore
96 is corrupt. It will be afterwards anyway :-)
98 Alert( AN_SemCorrupt );
100 #endif
103 Do not try and wake anything unless there are a number
104 of tasks waiting. We do both the tests, this is another
105 opportunity to throw an alert if there is an error.
108 sigSem->ss_QueueCount >= 0
109 && sigSem->ss_WaitQueue.mlh_Head->mln_Succ != NULL
112 struct SemaphoreRequest *sr, *srn;
115 Look at the first node, but only to see whether it
116 is shared or not.
118 sr = (struct SemaphoreRequest *)sigSem->ss_WaitQueue.mlh_Head;
121 A node is shared if the ln_Name/sr_Waiter field is
122 odd (ie it has bit 1 set).
124 If the sr_Waiter field is != NULL, then this is a
125 task waiting, otherwise it is a message.
127 if( ((IPTR)sr->sr_Waiter & SM_SHARED) == SM_SHARED )
129 /* This is a shared lock, so ss_Owner == NULL */
130 sigSem->ss_Owner = NULL;
132 /* Go through all the nodes to find the shared ones */
133 ForeachNodeSafe( &sigSem->ss_WaitQueue, sr, srn)
135 srn = (struct SemaphoreRequest *)sr->sr_Link.mln_Succ;
137 if( ((IPTR)sr->sr_Waiter & SM_SHARED) == SM_SHARED )
139 Remove((struct Node *)sr);
141 /* Clear the bit, and update the owner count */
142 sr->sr_Waiter = (APTR)((IPTR)sr->sr_Waiter & ~1);
143 sigSem->ss_NestCount++;
145 if(sr->sr_Waiter != NULL)
147 /* This is a task, signal it */
148 Signal(sr->sr_Waiter, SIGF_SINGLE);
150 else
152 /* This is a message, send it back to its owner */
153 ((struct SemaphoreMessage *)sr)->ssm_Semaphore = sigSem;
154 ReplyMsg((struct Message *)sr);
160 /* This is an exclusive lock - awaken first node */
161 else
163 /* Save typing */
164 struct SemaphoreMessage *sm = (struct SemaphoreMessage *)sr;
166 /* Only awaken the first of the nodes */
167 Remove((struct Node *)sr);
168 sigSem->ss_NestCount++;
170 if(sr->sr_Waiter != NULL)
172 sigSem->ss_Owner = sr->sr_Waiter;
173 Signal(sr->sr_Waiter, SIGF_SINGLE);
175 else
177 sigSem->ss_Owner = (struct Task *)sm->ssm_Semaphore;
178 sm->ssm_Semaphore = sigSem;
179 ReplyMsg((struct Message *)sr);
182 } /* there are waiters */
184 /* Otherwise, there are not tasks waiting. */
185 else
187 sigSem->ss_Owner = NULL;
188 sigSem->ss_QueueCount = -1;
190 D(bug("ReleaseSemaphore(): No tasks - ss_NestCount == %ld\n",
191 sigSem->ss_NestCount));
194 else if(sigSem->ss_NestCount < 0)
197 This can't happen. It means that somebody has released
198 more times than they have obtained.
200 Alert( AN_SemCorrupt );
203 /* All done. */
204 Permit();
206 AROS_LIBFUNC_EXIT
207 } /* ReleaseSemaphore */