vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / UserEvent.cpp
blob6e51a06d2e6827f2963898f4e331e3b6a302527e
1 /*
2 * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org.
3 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
8 #include <UserEvent.h>
10 #include <ksignal.h>
11 #include <thread_types.h>
12 #include <util/AutoLock.h>
15 // #pragma mark - UserEvent
18 UserEvent::~UserEvent()
23 // #pragma mark - SignalEvent
26 struct SignalEvent::EventSignal : Signal {
27 EventSignal(uint32 number, int32 signalCode, int32 errorCode,
28 pid_t sendingProcess)
30 Signal(number, signalCode, errorCode, sendingProcess),
31 fInUse(0)
35 bool MarkUsed()
37 return atomic_get_and_set(&fInUse, 1) != 0;
40 void SetUnused()
42 // mark not-in-use
43 atomic_set(&fInUse, 0);
46 virtual void Handled()
48 SetUnused();
50 Signal::Handled();
53 private:
54 int32 fInUse;
58 SignalEvent::SignalEvent(EventSignal* signal)
60 fSignal(signal),
61 fPendingDPC(0)
66 SignalEvent::~SignalEvent()
68 fSignal->ReleaseReference();
72 void
73 SignalEvent::SetUserValue(union sigval userValue)
75 fSignal->SetUserValue(userValue);
79 status_t
80 SignalEvent::Fire()
82 bool wasPending = atomic_get_and_set(&fPendingDPC, 1) != 0;
83 if (wasPending)
84 return B_BUSY;
86 if (fSignal->MarkUsed()) {
87 atomic_set(&fPendingDPC, 0);
88 return B_BUSY;
91 AcquireReference();
92 DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this);
94 return B_OK;
98 // #pragma mark - TeamSignalEvent
101 TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
103 SignalEvent(signal),
104 fTeam(team)
109 /*static*/ TeamSignalEvent*
110 TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
111 int32 errorCode)
113 // create the signal
114 EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
115 signalCode, errorCode, team->id);
116 if (signal == NULL)
117 return NULL;
119 // create the event
120 TeamSignalEvent* event = new TeamSignalEvent(team, signal);
121 if (event == NULL) {
122 delete signal;
123 return NULL;
126 return event;
130 status_t
131 TeamSignalEvent::Fire()
133 // We need a reference to the team to guarantee that it is still there when
134 // the DPC actually runs.
135 fTeam->AcquireReference();
136 status_t result = SignalEvent::Fire();
137 if (result != B_OK)
138 fTeam->ReleaseReference();
140 return result;
144 void
145 TeamSignalEvent::DoDPC(DPCQueue* queue)
147 fSignal->AcquireReference();
148 // one reference is transferred to send_signal_to_team_locked
150 InterruptsSpinLocker locker(fTeam->signal_lock);
151 status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
152 fSignal, B_DO_NOT_RESCHEDULE);
153 locker.Unlock();
154 fTeam->ReleaseReference();
156 // There are situations (for certain signals), in which
157 // send_signal_to_team_locked() succeeds without queuing the signal.
158 if (error != B_OK || !fSignal->IsPending())
159 fSignal->SetUnused();
161 // We're no longer queued in the DPC queue, so we can be reused.
162 atomic_set(&fPendingDPC, 0);
164 ReleaseReference();
168 // #pragma mark - ThreadSignalEvent
171 ThreadSignalEvent::ThreadSignalEvent(Thread* thread, EventSignal* signal)
173 SignalEvent(signal),
174 fThread(thread)
179 /*static*/ ThreadSignalEvent*
180 ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
181 int32 errorCode, pid_t sendingTeam)
183 // create the signal
184 EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
185 signalCode, errorCode, sendingTeam);
186 if (signal == NULL)
187 return NULL;
189 // create the event
190 ThreadSignalEvent* event = new ThreadSignalEvent(thread, signal);
191 if (event == NULL) {
192 delete signal;
193 return NULL;
196 return event;
200 status_t
201 ThreadSignalEvent::Fire()
203 // We need a reference to the thread to guarantee that it is still there
204 // when the DPC actually runs.
205 fThread->AcquireReference();
206 status_t result = SignalEvent::Fire();
207 if (result != B_OK)
208 fThread->ReleaseReference();
210 return result;
214 void
215 ThreadSignalEvent::DoDPC(DPCQueue* queue)
217 fSignal->AcquireReference();
218 // one reference is transferred to send_signal_to_team_locked
219 InterruptsReadSpinLocker teamLocker(fThread->team_lock);
220 SpinLocker locker(fThread->team->signal_lock);
221 status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
222 fSignal, B_DO_NOT_RESCHEDULE);
223 locker.Unlock();
224 teamLocker.Unlock();
225 fThread->ReleaseReference();
227 // There are situations (for certain signals), in which
228 // send_signal_to_team_locked() succeeds without queuing the signal.
229 if (error != B_OK || !fSignal->IsPending())
230 fSignal->SetUnused();
232 // We're no longer queued in the DPC queue, so we can be reused.
233 atomic_set(&fPendingDPC, 0);
235 ReleaseReference();
239 // #pragma mark - UserEvent
242 CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes)
244 fCreationAttributes(attributes),
245 fPendingDPC(0)
247 // attributes.name is a pointer to a temporary buffer. Copy the name into
248 // our own buffer and replace the name pointer.
249 strlcpy(fThreadName, attributes.name, sizeof(fThreadName));
250 fCreationAttributes.name = fThreadName;
254 /*static*/ CreateThreadEvent*
255 CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
257 return new(std::nothrow) CreateThreadEvent(attributes);
261 status_t
262 CreateThreadEvent::Fire()
264 bool wasPending = atomic_get_and_set(&fPendingDPC, 1) != 0;
265 if (wasPending)
266 return B_BUSY;
268 AcquireReference();
269 DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this);
271 return B_OK;
275 void
276 CreateThreadEvent::DoDPC(DPCQueue* queue)
278 // We're no longer queued in the DPC queue, so we can be reused.
279 atomic_set(&fPendingDPC, 0);
281 // create the thread
282 thread_id threadID = thread_create_thread(fCreationAttributes, false);
283 if (threadID >= 0)
284 resume_thread(threadID);
286 ReleaseReference();