xref: /haiku/src/system/kernel/UserEvent.cpp (revision e21d3133871123219b7aaefe79654196ac0ae681)
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