compiler/clib: Do not call __arosc_get_ctype() for each call to a ctype.h macro.
[AROS.git] / rom / exec / semaphores.c
blob178505bc954925f6e36af6dfc36ac06398fb4d68
1 /*
2 Copyright ¿ 1995-2011, The AROS Development Team. All rights reserved.
3 $Id: obtainsemaphore.c 43362 2011-12-30 07:45:42Z sonic $
5 Desc: Semaphore internal handling
6 Lang: english
7 */
9 #include <aros/atomic.h>
10 #include <aros/debug.h>
11 #include <proto/exec.h>
12 #include <proto/kernel.h>
14 #include "exec_util.h"
15 #include "semaphores.h"
17 BOOL CheckSemaphore(struct SignalSemaphore *sigSem, struct TraceLocation *caller, struct ExecBase *SysBase)
19 /* TODO: Introduce AlertContext for this */
21 if (KernelBase && KrnIsSuper())
23 /* FindTask() is called only here, for speedup */
24 struct Task *me = FindTask(NULL);
26 kprintf("%s called in supervisor mode!!!\n"
27 "sem = 0x%p task = 0x%p (%s)\n\n", caller->function, sigSem, me, me->tc_Node.ln_Name);
28 Exec_ExtAlert(ACPU_PrivErr & ~AT_DeadEnd, __builtin_return_address(0), CALLER_FRAME, 0, NULL, SysBase);
30 return FALSE;
33 if ((sigSem->ss_Link.ln_Type != NT_SIGNALSEM) || (sigSem->ss_WaitQueue.mlh_Tail != NULL))
35 struct Task *me = FindTask(NULL);
37 kprintf("%s called on a not intialized semaphore!!!\n"
38 "sem = 0x%p task = 0x%p (%s)\n\n", caller->function, sigSem, me, me->tc_Node.ln_Name);
39 Exec_ExtAlert(AN_SemCorrupt, __builtin_return_address(0), CALLER_FRAME, 0, NULL, SysBase);
41 return FALSE;
44 return TRUE;
47 void InternalObtainSemaphore(struct SignalSemaphore *sigSem, struct Task *owner, struct TraceLocation *caller, struct ExecBase *SysBase)
49 struct Task *me = FindTask(NULL);
52 * If there's no ThisTask, the function is called from within memory
53 * allocator in exec's pre-init code. We are already single-threaded,
54 * just return. :)
56 if (!me)
57 return;
60 * Freeing memory during RemTask(NULL). We are already single-threaded by
61 * Forbid(), and waiting isn't possible because task context is being deallocated.
63 if (me->tc_State == TS_REMOVED)
64 return;
66 if (!CheckSemaphore(sigSem, caller, SysBase))
67 return; /* A crude attempt to recover... */
70 * Arbitrate for the semaphore structure.
71 * TODO: SMP-aware versions of this code likely need to use spinlocks here
73 Forbid();
76 * ss_QueueCount == -1 indicates that the semaphore is
77 * free, so we increment this straight away. If it then
78 * equals 0, then we are the first to allocate this semaphore.
80 sigSem->ss_QueueCount++;
82 if (sigSem->ss_QueueCount == 0)
84 /* We now own the semaphore. This is quick. */
85 sigSem->ss_Owner = owner;
86 sigSem->ss_NestCount++;
89 * The semaphore is in use.
90 * It could be either shared (ss_Owner == NULL) or it could already be exclusively owned
91 * by me (ss_Owner == me).
92 * Exclusive or shared mode of this function is determined by 'owner' parameter.
93 * Actually it's pointer to a task which is allowed to share the lock with us.
94 * If it's equal to 'me', we are locking the semaphore in exclusive more. If it's NULL,
95 * we are locking in shared mode. This helps to optimize code against speed, and remove
96 * extra comparisons.
98 else if ((sigSem->ss_Owner == me) || (sigSem->ss_Owner == owner))
100 /* Yes, just increase the nesting count */
101 sigSem->ss_NestCount++;
103 /* Else, some other task owns it. We have to set a waiting request here. */
104 else
107 * We need a node to mark our semaphore request. Lets use some
108 * stack memory.
110 struct SemaphoreRequest sr;
111 sr.sr_Waiter = me;
114 * Have to clear the signal to make sure that we don't
115 * return immediately. We then add the SemReq to the
116 * waiters list of the semaphore. We were the last to
117 * request, so we must be the last to get the semaphore.
120 /* This must be atomic! */
121 AROS_ATOMIC_AND(me->tc_SigRecvd, ~SIGF_SINGLE);
123 AddTail((struct List *)&sigSem->ss_WaitQueue, (struct Node *)&sr);
126 * Finally, we simply wait, ReleaseSemaphore() will fill in
127 * who owns the semaphore.
129 Wait(SIGF_SINGLE);
132 /* All Done! */
133 Permit();
136 ULONG InternalAttemptSemaphore(struct SignalSemaphore *sigSem, struct Task *owner, struct TraceLocation *caller, struct ExecBase *SysBase)
138 struct Task *me = FindTask(NULL);
139 ULONG retval = TRUE;
141 if (!CheckSemaphore(sigSem, caller, SysBase))
142 return FALSE; /* A crude attempt to recover... */
145 * Arbitrate for the semaphore structure.
146 * TODO: SMP-aware versions of this code likely need to use spinlocks here
148 Forbid();
150 /* Increment the queue count */
151 sigSem->ss_QueueCount++;
153 if (sigSem->ss_QueueCount == 0)
155 /* The semaphore wasn't owned. We can now own it */
156 sigSem->ss_Owner = owner;
157 sigSem->ss_NestCount++;
159 else if ((sigSem->ss_Owner == me) || (sigSem->ss_Owner == owner))
161 /* The semaphore was owned by me or is shared, just increase the nest count */
162 sigSem->ss_NestCount++;
164 else
166 /* We can't get ownership, just return it. */
167 sigSem->ss_QueueCount--;
168 retval = FALSE;
171 /* All done. */
172 Permit();
174 return retval;