124df6592SIngo Weinhold /*
2d7e1e3e0SPawel Dziepak * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org.
324df6592SIngo Weinhold * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
424df6592SIngo Weinhold * Distributed under the terms of the MIT License.
524df6592SIngo Weinhold */
624df6592SIngo Weinhold
724df6592SIngo Weinhold
824df6592SIngo Weinhold #include <UserEvent.h>
924df6592SIngo Weinhold
1024df6592SIngo Weinhold #include <ksignal.h>
1124df6592SIngo Weinhold #include <thread_types.h>
1224df6592SIngo Weinhold #include <util/AutoLock.h>
1324df6592SIngo Weinhold
1424df6592SIngo Weinhold
1524df6592SIngo Weinhold // #pragma mark - UserEvent
1624df6592SIngo Weinhold
1724df6592SIngo Weinhold
~UserEvent()1824df6592SIngo Weinhold UserEvent::~UserEvent()
1924df6592SIngo Weinhold {
2024df6592SIngo Weinhold }
2124df6592SIngo Weinhold
2224df6592SIngo Weinhold
2324df6592SIngo Weinhold // #pragma mark - SignalEvent
2424df6592SIngo Weinhold
2524df6592SIngo Weinhold
2624df6592SIngo Weinhold struct SignalEvent::EventSignal : Signal {
EventSignalSignalEvent::EventSignal2724df6592SIngo Weinhold EventSignal(uint32 number, int32 signalCode, int32 errorCode,
2824df6592SIngo Weinhold pid_t sendingProcess)
2924df6592SIngo Weinhold :
3024df6592SIngo Weinhold Signal(number, signalCode, errorCode, sendingProcess),
31f4b088a9SPawel Dziepak fInUse(0)
3224df6592SIngo Weinhold {
3324df6592SIngo Weinhold }
3424df6592SIngo Weinhold
MarkUsedSignalEvent::EventSignal35958f6d00SPawel Dziepak bool MarkUsed()
3624df6592SIngo Weinhold {
37077c84ebSPawel Dziepak return atomic_get_and_set(&fInUse, 1) != 0;
3824df6592SIngo Weinhold }
3924df6592SIngo Weinhold
SetUnusedSignalEvent::EventSignal40958f6d00SPawel Dziepak void SetUnused()
4124df6592SIngo Weinhold {
42e7dba861SPawel Dziepak // mark not-in-use
43e7dba861SPawel Dziepak atomic_set(&fInUse, 0);
4424df6592SIngo Weinhold }
4524df6592SIngo Weinhold
HandledSignalEvent::EventSignal4624df6592SIngo Weinhold virtual void Handled()
4724df6592SIngo Weinhold {
48e7dba861SPawel Dziepak SetUnused();
4924df6592SIngo Weinhold
5024df6592SIngo Weinhold Signal::Handled();
5124df6592SIngo Weinhold }
5224df6592SIngo Weinhold
5324df6592SIngo Weinhold private:
54f4b088a9SPawel Dziepak int32 fInUse;
5524df6592SIngo Weinhold };
5624df6592SIngo Weinhold
5724df6592SIngo Weinhold
SignalEvent(EventSignal * signal)5824df6592SIngo Weinhold SignalEvent::SignalEvent(EventSignal* signal)
5924df6592SIngo Weinhold :
6003451e4cSPawel Dziepak fSignal(signal),
6103451e4cSPawel Dziepak fPendingDPC(0)
6224df6592SIngo Weinhold {
6324df6592SIngo Weinhold }
6424df6592SIngo Weinhold
6524df6592SIngo Weinhold
~SignalEvent()6624df6592SIngo Weinhold SignalEvent::~SignalEvent()
6724df6592SIngo Weinhold {
6824df6592SIngo Weinhold fSignal->ReleaseReference();
6924df6592SIngo Weinhold }
7024df6592SIngo Weinhold
7124df6592SIngo Weinhold
7224df6592SIngo Weinhold void
SetUserValue(union sigval userValue)7324df6592SIngo Weinhold SignalEvent::SetUserValue(union sigval userValue)
7424df6592SIngo Weinhold {
7524df6592SIngo Weinhold fSignal->SetUserValue(userValue);
7624df6592SIngo Weinhold }
7724df6592SIngo Weinhold
7824df6592SIngo Weinhold
7903451e4cSPawel Dziepak status_t
Fire()8003451e4cSPawel Dziepak SignalEvent::Fire()
8103451e4cSPawel Dziepak {
8203451e4cSPawel Dziepak bool wasPending = atomic_get_and_set(&fPendingDPC, 1) != 0;
8303451e4cSPawel Dziepak if (wasPending)
8403451e4cSPawel Dziepak return B_BUSY;
8503451e4cSPawel Dziepak
8603451e4cSPawel Dziepak if (fSignal->MarkUsed()) {
8703451e4cSPawel Dziepak atomic_set(&fPendingDPC, 0);
8803451e4cSPawel Dziepak return B_BUSY;
8903451e4cSPawel Dziepak }
9003451e4cSPawel Dziepak
91d7e1e3e0SPawel Dziepak AcquireReference();
9203451e4cSPawel Dziepak DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this);
9303451e4cSPawel Dziepak
9403451e4cSPawel Dziepak return B_OK;
9503451e4cSPawel Dziepak }
9603451e4cSPawel Dziepak
9703451e4cSPawel Dziepak
9824df6592SIngo Weinhold // #pragma mark - TeamSignalEvent
9924df6592SIngo Weinhold
10024df6592SIngo Weinhold
TeamSignalEvent(Team * team,EventSignal * signal)10124df6592SIngo Weinhold TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
10224df6592SIngo Weinhold :
10324df6592SIngo Weinhold SignalEvent(signal),
10424df6592SIngo Weinhold fTeam(team)
10524df6592SIngo Weinhold {
10624df6592SIngo Weinhold }
10724df6592SIngo Weinhold
10824df6592SIngo Weinhold
10924df6592SIngo Weinhold /*static*/ TeamSignalEvent*
Create(Team * team,uint32 signalNumber,int32 signalCode,int32 errorCode)11024df6592SIngo Weinhold TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
11124df6592SIngo Weinhold int32 errorCode)
11224df6592SIngo Weinhold {
11324df6592SIngo Weinhold // create the signal
11424df6592SIngo Weinhold EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
11524df6592SIngo Weinhold signalCode, errorCode, team->id);
11624df6592SIngo Weinhold if (signal == NULL)
11724df6592SIngo Weinhold return NULL;
11824df6592SIngo Weinhold
11924df6592SIngo Weinhold // create the event
120*e21d3133SJérôme Duval TeamSignalEvent* event = new(std::nothrow) TeamSignalEvent(team, signal);
12124df6592SIngo Weinhold if (event == NULL) {
12224df6592SIngo Weinhold delete signal;
12324df6592SIngo Weinhold return NULL;
12424df6592SIngo Weinhold }
12524df6592SIngo Weinhold
12624df6592SIngo Weinhold return event;
12724df6592SIngo Weinhold }
12824df6592SIngo Weinhold
12924df6592SIngo Weinhold
1306a80e688SMichael Lotz status_t
Fire()1316a80e688SMichael Lotz TeamSignalEvent::Fire()
1326a80e688SMichael Lotz {
1336a80e688SMichael Lotz // We need a reference to the team to guarantee that it is still there when
1346a80e688SMichael Lotz // the DPC actually runs.
1356a80e688SMichael Lotz fTeam->AcquireReference();
1366a80e688SMichael Lotz status_t result = SignalEvent::Fire();
1376a80e688SMichael Lotz if (result != B_OK)
1386a80e688SMichael Lotz fTeam->ReleaseReference();
1396a80e688SMichael Lotz
1406a80e688SMichael Lotz return result;
1416a80e688SMichael Lotz }
1426a80e688SMichael Lotz
1436a80e688SMichael Lotz
14403451e4cSPawel Dziepak void
DoDPC(DPCQueue * queue)14503451e4cSPawel Dziepak TeamSignalEvent::DoDPC(DPCQueue* queue)
14624df6592SIngo Weinhold {
14724df6592SIngo Weinhold fSignal->AcquireReference();
14824df6592SIngo Weinhold // one reference is transferred to send_signal_to_team_locked
149958f6d00SPawel Dziepak
150aa4aca02SPawel Dziepak InterruptsSpinLocker locker(fTeam->signal_lock);
15124df6592SIngo Weinhold status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
15224df6592SIngo Weinhold fSignal, B_DO_NOT_RESCHEDULE);
153e7dba861SPawel Dziepak locker.Unlock();
1546a80e688SMichael Lotz fTeam->ReleaseReference();
155e7dba861SPawel Dziepak
156958f6d00SPawel Dziepak // There are situations (for certain signals), in which
157958f6d00SPawel Dziepak // send_signal_to_team_locked() succeeds without queuing the signal.
158f4b088a9SPawel Dziepak if (error != B_OK || !fSignal->IsPending())
159958f6d00SPawel Dziepak fSignal->SetUnused();
16024df6592SIngo Weinhold
16103451e4cSPawel Dziepak // We're no longer queued in the DPC queue, so we can be reused.
16203451e4cSPawel Dziepak atomic_set(&fPendingDPC, 0);
163d7e1e3e0SPawel Dziepak
164d7e1e3e0SPawel Dziepak ReleaseReference();
16524df6592SIngo Weinhold }
16624df6592SIngo Weinhold
16724df6592SIngo Weinhold
16824df6592SIngo Weinhold // #pragma mark - ThreadSignalEvent
16924df6592SIngo Weinhold
17024df6592SIngo Weinhold
ThreadSignalEvent(Thread * thread,EventSignal * signal)17124df6592SIngo Weinhold ThreadSignalEvent::ThreadSignalEvent(Thread* thread, EventSignal* signal)
17224df6592SIngo Weinhold :
17324df6592SIngo Weinhold SignalEvent(signal),
17424df6592SIngo Weinhold fThread(thread)
17524df6592SIngo Weinhold {
17624df6592SIngo Weinhold }
17724df6592SIngo Weinhold
17824df6592SIngo Weinhold
17924df6592SIngo Weinhold /*static*/ ThreadSignalEvent*
Create(Thread * thread,uint32 signalNumber,int32 signalCode,int32 errorCode,pid_t sendingTeam)18024df6592SIngo Weinhold ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
18124df6592SIngo Weinhold int32 errorCode, pid_t sendingTeam)
18224df6592SIngo Weinhold {
18324df6592SIngo Weinhold // create the signal
18424df6592SIngo Weinhold EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
18524df6592SIngo Weinhold signalCode, errorCode, sendingTeam);
18624df6592SIngo Weinhold if (signal == NULL)
18724df6592SIngo Weinhold return NULL;
18824df6592SIngo Weinhold
18924df6592SIngo Weinhold // create the event
190*e21d3133SJérôme Duval ThreadSignalEvent* event = new(std::nothrow) ThreadSignalEvent(thread, signal);
19124df6592SIngo Weinhold if (event == NULL) {
19224df6592SIngo Weinhold delete signal;
19324df6592SIngo Weinhold return NULL;
19424df6592SIngo Weinhold }
19524df6592SIngo Weinhold
19624df6592SIngo Weinhold return event;
19724df6592SIngo Weinhold }
19824df6592SIngo Weinhold
19924df6592SIngo Weinhold
2006a80e688SMichael Lotz status_t
Fire()2016a80e688SMichael Lotz ThreadSignalEvent::Fire()
2026a80e688SMichael Lotz {
2036a80e688SMichael Lotz // We need a reference to the thread to guarantee that it is still there
2046a80e688SMichael Lotz // when the DPC actually runs.
2056a80e688SMichael Lotz fThread->AcquireReference();
2066a80e688SMichael Lotz status_t result = SignalEvent::Fire();
2076a80e688SMichael Lotz if (result != B_OK)
2086a80e688SMichael Lotz fThread->ReleaseReference();
2096a80e688SMichael Lotz
2106a80e688SMichael Lotz return result;
2116a80e688SMichael Lotz }
2126a80e688SMichael Lotz
2136a80e688SMichael Lotz
21403451e4cSPawel Dziepak void
DoDPC(DPCQueue * queue)21503451e4cSPawel Dziepak ThreadSignalEvent::DoDPC(DPCQueue* queue)
21624df6592SIngo Weinhold {
21724df6592SIngo Weinhold fSignal->AcquireReference();
21824df6592SIngo Weinhold // one reference is transferred to send_signal_to_team_locked
2193519eb33SPawel Dziepak InterruptsReadSpinLocker teamLocker(fThread->team_lock);
220aa4aca02SPawel Dziepak SpinLocker locker(fThread->team->signal_lock);
22124df6592SIngo Weinhold status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
22224df6592SIngo Weinhold fSignal, B_DO_NOT_RESCHEDULE);
223e7dba861SPawel Dziepak locker.Unlock();
224aa4aca02SPawel Dziepak teamLocker.Unlock();
2256a80e688SMichael Lotz fThread->ReleaseReference();
226e7dba861SPawel Dziepak
227958f6d00SPawel Dziepak // There are situations (for certain signals), in which
228958f6d00SPawel Dziepak // send_signal_to_team_locked() succeeds without queuing the signal.
229f4b088a9SPawel Dziepak if (error != B_OK || !fSignal->IsPending())
230958f6d00SPawel Dziepak fSignal->SetUnused();
23124df6592SIngo Weinhold
23203451e4cSPawel Dziepak // We're no longer queued in the DPC queue, so we can be reused.
23303451e4cSPawel Dziepak atomic_set(&fPendingDPC, 0);
234d7e1e3e0SPawel Dziepak
235d7e1e3e0SPawel Dziepak ReleaseReference();
23624df6592SIngo Weinhold }
23724df6592SIngo Weinhold
23824df6592SIngo Weinhold
23924df6592SIngo Weinhold // #pragma mark - UserEvent
24024df6592SIngo Weinhold
24124df6592SIngo Weinhold
CreateThreadEvent(const ThreadCreationAttributes & attributes)24224df6592SIngo Weinhold CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes)
24324df6592SIngo Weinhold :
24424df6592SIngo Weinhold fCreationAttributes(attributes),
245f4b088a9SPawel Dziepak fPendingDPC(0)
24624df6592SIngo Weinhold {
24724df6592SIngo Weinhold // attributes.name is a pointer to a temporary buffer. Copy the name into
24824df6592SIngo Weinhold // our own buffer and replace the name pointer.
24924df6592SIngo Weinhold strlcpy(fThreadName, attributes.name, sizeof(fThreadName));
25024df6592SIngo Weinhold fCreationAttributes.name = fThreadName;
25124df6592SIngo Weinhold }
25224df6592SIngo Weinhold
25324df6592SIngo Weinhold
25424df6592SIngo Weinhold /*static*/ CreateThreadEvent*
Create(const ThreadCreationAttributes & attributes)25524df6592SIngo Weinhold CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
25624df6592SIngo Weinhold {
25724df6592SIngo Weinhold return new(std::nothrow) CreateThreadEvent(attributes);
25824df6592SIngo Weinhold }
25924df6592SIngo Weinhold
26024df6592SIngo Weinhold
26124df6592SIngo Weinhold status_t
Fire()26224df6592SIngo Weinhold CreateThreadEvent::Fire()
26324df6592SIngo Weinhold {
264077c84ebSPawel Dziepak bool wasPending = atomic_get_and_set(&fPendingDPC, 1) != 0;
265958f6d00SPawel Dziepak if (wasPending)
26624df6592SIngo Weinhold return B_BUSY;
26724df6592SIngo Weinhold
268d7e1e3e0SPawel Dziepak AcquireReference();
269958f6d00SPawel Dziepak DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this);
27024df6592SIngo Weinhold
27124df6592SIngo Weinhold return B_OK;
27224df6592SIngo Weinhold }
27324df6592SIngo Weinhold
27424df6592SIngo Weinhold
27524df6592SIngo Weinhold void
DoDPC(DPCQueue * queue)27624df6592SIngo Weinhold CreateThreadEvent::DoDPC(DPCQueue* queue)
27724df6592SIngo Weinhold {
27824df6592SIngo Weinhold // We're no longer queued in the DPC queue, so we can be reused.
279e7dba861SPawel Dziepak atomic_set(&fPendingDPC, 0);
28024df6592SIngo Weinhold
28124df6592SIngo Weinhold // create the thread
28224df6592SIngo Weinhold thread_id threadID = thread_create_thread(fCreationAttributes, false);
28324df6592SIngo Weinhold if (threadID >= 0)
28424df6592SIngo Weinhold resume_thread(threadID);
285bf685cdfSMichael Lotz
286bf685cdfSMichael Lotz ReleaseReference();
28724df6592SIngo Weinhold }
288