xref: /haiku/src/system/kernel/UserEvent.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <UserEvent.h>
8 
9 #include <ksignal.h>
10 #include <thread_types.h>
11 #include <util/AutoLock.h>
12 
13 
14 // #pragma mark - UserEvent
15 
16 
17 UserEvent::~UserEvent()
18 {
19 }
20 
21 
22 // #pragma mark - SignalEvent
23 
24 
25 struct SignalEvent::EventSignal : Signal {
26 	EventSignal(uint32 number, int32 signalCode, int32 errorCode,
27 		pid_t sendingProcess)
28 		:
29 		Signal(number, signalCode, errorCode, sendingProcess),
30 		fInUse(false)
31 	{
32 	}
33 
34 	bool IsInUse() const
35 	{
36 		return fInUse;
37 	}
38 
39 	void SetInUse(bool inUse)
40 	{
41 		fInUse = inUse;
42 	}
43 
44 	virtual void Handled()
45 	{
46 		// mark not-in-use
47 		InterruptsSpinLocker schedulerLocker(gSchedulerLock);
48 		fInUse = false;
49 		schedulerLocker.Unlock();
50 
51 		Signal::Handled();
52 	}
53 
54 private:
55 	bool				fInUse;
56 };
57 
58 
59 SignalEvent::SignalEvent(EventSignal* signal)
60 	:
61 	fSignal(signal)
62 {
63 }
64 
65 
66 SignalEvent::~SignalEvent()
67 {
68 	fSignal->ReleaseReference();
69 }
70 
71 
72 void
73 SignalEvent::SetUserValue(union sigval userValue)
74 {
75 	fSignal->SetUserValue(userValue);
76 }
77 
78 
79 // #pragma mark - TeamSignalEvent
80 
81 
82 TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
83 	:
84 	SignalEvent(signal),
85 	fTeam(team)
86 {
87 }
88 
89 
90 /*static*/ TeamSignalEvent*
91 TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
92 	int32 errorCode)
93 {
94 	// create the signal
95 	EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
96 		signalCode, errorCode, team->id);
97 	if (signal == NULL)
98 		return NULL;
99 
100 	// create the event
101 	TeamSignalEvent* event = new TeamSignalEvent(team, signal);
102 	if (event == NULL) {
103 		delete signal;
104 		return NULL;
105 	}
106 
107 	return event;
108 }
109 
110 
111 status_t
112 TeamSignalEvent::Fire()
113 {
114 	// called with the scheduler lock held
115 	if (fSignal->IsInUse())
116 		return B_BUSY;
117 
118 	fSignal->AcquireReference();
119 		// one reference is transferred to send_signal_to_team_locked
120 	status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
121 		fSignal, B_DO_NOT_RESCHEDULE);
122 	if (error == B_OK) {
123 		// Mark the signal in-use. There are situations (for certain signals),
124 		// in which send_signal_to_team_locked() succeeds without queuing the
125 		// signal.
126 		fSignal->SetInUse(fSignal->IsPending());
127 	}
128 
129 	return error;
130 }
131 
132 
133 // #pragma mark - ThreadSignalEvent
134 
135 
136 ThreadSignalEvent::ThreadSignalEvent(Thread* thread, EventSignal* signal)
137 	:
138 	SignalEvent(signal),
139 	fThread(thread)
140 {
141 }
142 
143 
144 /*static*/ ThreadSignalEvent*
145 ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
146 	int32 errorCode, pid_t sendingTeam)
147 {
148 	// create the signal
149 	EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
150 		signalCode, errorCode, sendingTeam);
151 	if (signal == NULL)
152 		return NULL;
153 
154 	// create the event
155 	ThreadSignalEvent* event = new ThreadSignalEvent(thread, signal);
156 	if (event == NULL) {
157 		delete signal;
158 		return NULL;
159 	}
160 
161 	return event;
162 }
163 
164 
165 status_t
166 ThreadSignalEvent::Fire()
167 {
168 	// called with the scheduler lock held
169 	if (fSignal->IsInUse())
170 		return B_BUSY;
171 
172 	fSignal->AcquireReference();
173 		// one reference is transferred to send_signal_to_team_locked
174 	status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
175 		fSignal, B_DO_NOT_RESCHEDULE);
176 	if (error == B_OK) {
177 		// Mark the signal in-use. There are situations (for certain signals),
178 		// in which send_signal_to_team_locked() succeeds without queuing the
179 		// signal.
180 		fSignal->SetInUse(fSignal->IsPending());
181 	}
182 
183 	return error;
184 }
185 
186 
187 // #pragma mark - UserEvent
188 
189 
190 CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes)
191 	:
192 	fCreationAttributes(attributes),
193 	fPendingDPC(false)
194 {
195 	// attributes.name is a pointer to a temporary buffer. Copy the name into
196 	// our own buffer and replace the name pointer.
197 	strlcpy(fThreadName, attributes.name, sizeof(fThreadName));
198 	fCreationAttributes.name = fThreadName;
199 }
200 
201 
202 CreateThreadEvent::~CreateThreadEvent()
203 {
204 	// cancel the DPC to be on the safe side
205 	DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Cancel(this);
206 }
207 
208 
209 /*static*/ CreateThreadEvent*
210 CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
211 {
212 	return new(std::nothrow) CreateThreadEvent(attributes);
213 }
214 
215 
216 status_t
217 CreateThreadEvent::Fire()
218 {
219 	if (fPendingDPC)
220 		return B_BUSY;
221 
222 	fPendingDPC = true;
223 
224 	DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this, true);
225 
226 	return B_OK;
227 }
228 
229 
230 void
231 CreateThreadEvent::DoDPC(DPCQueue* queue)
232 {
233 	// We're no longer queued in the DPC queue, so we can be reused.
234 	{
235 		InterruptsSpinLocker schedulerLocker(gSchedulerLock);
236 		fPendingDPC = false;
237 	}
238 
239 	// create the thread
240 	thread_id threadID = thread_create_thread(fCreationAttributes, false);
241 	if (threadID >= 0)
242 		resume_thread(threadID);
243 }
244