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
1824df6592SIngo WeinholdUserEvent::~UserEvent()
1924df6592SIngo Weinhold{
2024df6592SIngo Weinhold}
2124df6592SIngo Weinhold
2224df6592SIngo Weinhold
2324df6592SIngo Weinhold// #pragma mark - SignalEvent
2424df6592SIngo Weinhold
2524df6592SIngo Weinhold
2624df6592SIngo Weinholdstruct SignalEvent::EventSignal : Signal {
2724df6592SIngo 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
35958f6d00SPawel Dziepak	bool MarkUsed()
3624df6592SIngo Weinhold	{
37077c84ebSPawel Dziepak		return atomic_get_and_set(&fInUse, 1) != 0;
3824df6592SIngo Weinhold	}
3924df6592SIngo Weinhold
40958f6d00SPawel Dziepak	void SetUnused()
4124df6592SIngo Weinhold	{
42e7dba861SPawel Dziepak		// mark not-in-use
43e7dba861SPawel Dziepak		atomic_set(&fInUse, 0);
4424df6592SIngo Weinhold	}
4524df6592SIngo Weinhold
4624df6592SIngo Weinhold	virtual void Handled()
4724df6592SIngo Weinhold	{
48e7dba861SPawel Dziepak		SetUnused();
4924df6592SIngo Weinhold
5024df6592SIngo Weinhold		Signal::Handled();
5124df6592SIngo Weinhold	}
5224df6592SIngo Weinhold
5324df6592SIngo Weinholdprivate:
54f4b088a9SPawel Dziepak	int32				fInUse;
5524df6592SIngo Weinhold};
5624df6592SIngo Weinhold
5724df6592SIngo Weinhold
5824df6592SIngo WeinholdSignalEvent::SignalEvent(EventSignal* signal)
5924df6592SIngo Weinhold	:
6003451e4cSPawel Dziepak	fSignal(signal),
6103451e4cSPawel Dziepak	fPendingDPC(0)
6224df6592SIngo Weinhold{
6324df6592SIngo Weinhold}
6424df6592SIngo Weinhold
6524df6592SIngo Weinhold
6624df6592SIngo WeinholdSignalEvent::~SignalEvent()
6724df6592SIngo Weinhold{
6824df6592SIngo Weinhold	fSignal->ReleaseReference();
6924df6592SIngo Weinhold}
7024df6592SIngo Weinhold
7124df6592SIngo Weinhold
7224df6592SIngo Weinholdvoid
7324df6592SIngo WeinholdSignalEvent::SetUserValue(union sigval userValue)
7424df6592SIngo Weinhold{
7524df6592SIngo Weinhold	fSignal->SetUserValue(userValue);
7624df6592SIngo Weinhold}
7724df6592SIngo Weinhold
7824df6592SIngo Weinhold
7903451e4cSPawel Dziepakstatus_t
8003451e4cSPawel DziepakSignalEvent::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
10124df6592SIngo WeinholdTeamSignalEvent::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*
11024df6592SIngo WeinholdTeamSignalEvent::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
12024df6592SIngo Weinhold	TeamSignalEvent* event = new 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 Lotzstatus_t
1316a80e688SMichael LotzTeamSignalEvent::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 Dziepakvoid
14503451e4cSPawel DziepakTeamSignalEvent::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
156f4b088a9SPawel Dziepak	// There are situations (for certain signals), in which
157f4b088a9SPawel Dziepak	// send_signal_to_team_locked() succeeds without queuing the signal.
158f4b088a9SPawel Dziepak	if (error != B_OK || !fSignal->IsPending())
159f4b088a9SPawel 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
17124df6592SIngo WeinholdThreadSignalEvent::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*
18024df6592SIngo WeinholdThreadSignalEvent::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
19024df6592SIngo Weinhold	ThreadSignalEvent* event = new 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 Lotzstatus_t
2016a80e688SMichael LotzThreadSignalEvent::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 Dziepakvoid
21503451e4cSPawel DziepakThreadSignalEvent::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
227f4b088a9SPawel Dziepak	// There are situations (for certain signals), in which
228f4b088a9SPawel Dziepak	// send_signal_to_team_locked() succeeds without queuing the signal.
229f4b088a9SPawel Dziepak	if (error != B_OK || !fSignal->IsPending())
230f4b088a9SPawel 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
24224df6592SIngo WeinholdCreateThreadEvent::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*
25524df6592SIngo WeinholdCreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
25624df6592SIngo Weinhold{
25724df6592SIngo Weinhold	return new(std::nothrow) CreateThreadEvent(attributes);
25824df6592SIngo Weinhold}
25924df6592SIngo Weinhold
26024df6592SIngo Weinhold
26124df6592SIngo Weinholdstatus_t
26224df6592SIngo WeinholdCreateThreadEvent::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 Weinholdvoid
27624df6592SIngo WeinholdCreateThreadEvent::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