use GET_THIS_TASK internally throughout exec - since it will result in faster/smaller...
[AROS.git] / rom / exec / allocsignal.c
blob6fee94d652da801526f16367af8e35656abf41c2
1 /*
2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Allocate a signal
6 Lang: english
7 */
9 #include <exec/execbase.h>
10 #include <exec/tasks.h>
11 #include <aros/libcall.h>
12 #include <proto/exec.h>
14 #include "exec_util.h"
15 #if defined(__AROSEXEC_SMP__)
16 #include "etask.h"
17 #endif
19 /*****************************************************************************
21 NAME */
23 AROS_LH1(BYTE, AllocSignal,
25 /* SYNOPSIS */
26 AROS_LHA(LONG, signalNum, D0),
28 /* LOCATION */
29 struct ExecBase *, SysBase, 55, Exec)
31 /* FUNCTION
32 Allocate a given signal out of the current task's pool of signals.
33 Every task has a set of signals to communicate with other tasks.
34 Half of them are reserved for the system and half of them are
35 free for general use. Some of the reserved signals (e.g.
36 SIGBREAKF_CTRL_C) have a defined behaviour and may be used by user
37 code, however.
39 You must not allocate or free signals from exception handlers.
41 INPUTS
42 signalNum - Number of the signal to allocate or -1 if any signal
43 will do.
45 RESULT
46 Number of the signal or -1 if the signal couldn't be allocated.
48 NOTES
50 EXAMPLE
52 BUGS
54 SEE ALSO
55 FreeSignal(), Signal(), Wait()
57 INTERNALS
59 ******************************************************************************/
61 AROS_LIBFUNC_INIT
63 /* Cast signalNum to BYTE for AOS/68k compatibility. Apps may set up only D0.b */
64 return AllocTaskSignal(GET_THIS_TASK, (BYTE)signalNum, SysBase);
66 AROS_LIBFUNC_EXIT
67 } /* AllocSignal() */
69 LONG AllocTaskSignal(struct Task *ThisTask, LONG signalNum, struct ExecBase *SysBase)
71 ULONG mask;
72 ULONG mask1;
74 mask = ThisTask->tc_SigAlloc;
76 /* Will any signal do? */
77 if(signalNum < 0)
80 * To get the last nonzero bit in a number I use a&~a+1:
81 * Given a number that ends with a row of zeros xxxx1000
82 * I first toggle all bits in that number XXXX0111
83 * then add 1 to toggle all but the last 0 again XXXX1000
84 * and AND this with the original number 00001000
86 * And since ~a+1=-a I can use a&-a instead.
88 * And to get the last zero bit I finally use ~a&-~a.
90 mask1 = ~mask & - ~mask;
92 /* Is the bit already allocated? */
93 if(mask1 == 0)
94 return -1;
96 /* And get the bit number */
97 signalNum=(mask1&0xffff0000?16:0)+(mask1&0xff00ff00?8:0)+
98 (mask1&0xf0f0f0f0? 4:0)+(mask1&0xcccccccc?2:0)+
99 (mask1&0xaaaaaaaa? 1:0);
101 else
103 mask1 = 1L << signalNum;
105 /* If signal bit is already allocated, return. */
106 if(ThisTask->tc_SigAlloc & mask1)
107 return -1;
111 * I shouldn't need to disable around changing the signal masks
112 * because the only thing allowed to change the mask of allocated,
113 * excepting and waiting signals is the task itself. On the other
114 * hand, I need to use Disable around the received signals because it
115 * can be modified by interrupts, and I cannot rely upon the below
116 * being atomic.
119 ThisTask->tc_SigAlloc |= mask1;
120 ThisTask->tc_SigExcept &= ~mask1;
121 ThisTask->tc_SigWait &= ~mask1;
123 #if defined(__AROSEXEC_SMP__)
124 EXEC_SPINLOCK_LOCK(&IntETask(ThisTask->tc_UnionETask.tc_ETask)->iet_TaskLock, SPINLOCK_MODE_WRITE);
125 #endif
126 Disable();
128 ThisTask->tc_SigRecvd &= ~mask1;
130 #if defined(__AROSEXEC_SMP__)
131 EXEC_SPINLOCK_UNLOCK(&IntETask(ThisTask->tc_UnionETask.tc_ETask)->iet_TaskLock);
132 #endif
133 Enable();
135 return signalNum;