The Pedigree Project 0.1
PosixProcess.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "PosixProcess.h"
21#include "pedigree/kernel/process/Scheduler.h"
22#include "pedigree/kernel/utilities/utility.h"
23
24#include <signal.h>
25
26#include "IntervalTimerState.h"
27#include "ProcFs.h"
28#include "TerminalControl.h"
29#include "modules/system/vfs/VFS.h"
30
31PosixProcess::PosixProcess()
32 : Process(DeferredPublication(), Posix),
33 m_AccountingLifetime(false),
34 m_SessionId(0),
35 m_pProcessGroup(nullptr),
36 m_GroupPrevious(nullptr),
37 m_GroupNext(nullptr),
38 m_ExecCommitted(false),
39 m_GroupMembership(NoGroup),
40 m_Mask(0),
41 m_RealIntervalTimer(this, IntervalTimer::Hardware),
42 m_VirtualIntervalTimer(this, IntervalTimer::Virtual),
43 m_ProfileIntervalTimer(this, IntervalTimer::Profile),
44 m_Credentials(),
45 m_RealUserId(0),
46 m_bRegistered(false) {
47 initializeJobControl(nullptr);
48 publishCredentialReadCache();
49 enableTimeAccountingReports(0);
50}
51
53PosixProcess::PosixProcess(Process* pParent, bool bCopyOnWrite,
54 FilesystemContextMode filesystemContext, bool emptyAddressSpace)
55 : Process(DeferredPublication(), pParent, bCopyOnWrite, filesystemContext, emptyAddressSpace,
56 Posix),
57 m_AccountingLifetime(true),
58 m_SessionId(0),
59 m_pProcessGroup(nullptr),
60 m_GroupPrevious(nullptr),
61 m_GroupNext(nullptr),
62 m_ExecCommitted(false),
63 m_GroupMembership(NoGroup),
64 m_Mask(0),
65 m_RealIntervalTimer(this, IntervalTimer::Hardware),
66 m_VirtualIntervalTimer(this, IntervalTimer::Virtual),
67 m_ProfileIntervalTimer(this, IntervalTimer::Profile),
68 m_Credentials(),
69 m_RealUserId(0),
70 m_bRegistered(false) {
71 initializeJobControl(pParent);
73
74 if (pParent->getType() == Posix) {
75 PosixProcess* pPosixParent = static_cast<PosixProcess*>(pParent);
76
77 // Child inherits parent's mask.
78 m_Mask = pPosixParent->getMask();
79
80 m_Credentials = pPosixParent->snapshotCredentials();
81 } else {
82 FilesystemCredentials inherited;
83 if (pParent->snapshotFilesystemCredentials(nullptr, inherited)) {
84 m_Credentials.ruid = m_Credentials.euid = m_Credentials.suid = inherited.uid;
85 m_Credentials.rgid = m_Credentials.egid = m_Credentials.sgid = inherited.gid;
86 m_Credentials.groupCount = inherited.groupCount;
87 for (size_t i = 0; i < inherited.groupCount; ++i)
88 m_Credentials.groups[i] = inherited.groups[i];
89 }
90 }
91 publishCredentialReadCache();
92}
93
94void PosixProcess::publishCredentialReadCache() {
95 __atomic_store_n(&m_RealUserId, m_Credentials.ruid, __ATOMIC_RELEASE);
96}
97
98PosixProcess::~PosixProcess() {
100 leaveProcessGroup();
101 unregisterProcess();
102}
103
105 // Scheduler enumeration must not observe this object until the caller has
106 // installed all child-side state and a non-runnable initial Thread.
107 assert(jobControlReady());
109 registerProcess();
110}
111
112void PosixProcess::setMask(uint32_t mask) {
113 m_Mask = mask;
114}
115
116uint32_t PosixProcess::getMask() const {
117 return m_Mask;
118}
119
120void PosixProcess::registerProcess() {
121 ProcFs::publishProcess(this);
122 m_bRegistered = true;
123 if (!pidNamespaceReady()) {
124 ThreadLease recipient;
125 if (getSubsystem() && acquireProcessSignalThread(recipient)) {
126 getSubsystem()->kill(Subsystem::Unknown, recipient.get());
127 }
128 }
129}
130
131void PosixProcess::unregisterProcess() {
132 if (m_bRegistered) {
133 ProcFs::unpublishProcess(this);
134 m_bRegistered = false;
135 }
136}
137
138IntervalTimer& PosixProcess::getRealIntervalTimer() {
139 return m_RealIntervalTimer;
140}
141
142IntervalTimer& PosixProcess::getVirtualIntervalTimer() {
143 return m_VirtualIntervalTimer;
144}
145
146IntervalTimer& PosixProcess::getProfileIntervalTimer() {
147 return m_ProfileIntervalTimer;
148}
149
150void PosixProcess::reportTimesUpdated(Time::Timestamp userTotal, Time::Timestamp total) {
151 m_VirtualIntervalTimer.consumeCpuTime(userTotal);
152 m_ProfileIntervalTimer.consumeCpuTime(total);
153}
154
156 // Cancel all timers.
157 m_RealIntervalTimer.disarm();
158 m_VirtualIntervalTimer.disarm();
159 m_ProfileIntervalTimer.disarm();
160 posix_account_process_exit(*this, m_AccountingLifetime);
161 TerminalControl::processTerminated(*this);
162}
163
165 : m_Process(pProcess),
166 m_Mode(mode),
167 m_Value(0),
168 m_Interval(0),
169 m_LastTotal(0),
170 m_Lock(false),
171 m_Armed(false),
172 m_pTimer(nullptr) {
173 m_LastTotal = absoluteTotal();
174 if (m_Mode == Hardware) {
175 Timer* t = Machine::instance().getTimer();
176 if (t && t->registerHandler(this)) {
177 m_pTimer = t;
178 } else {
179 ERROR("IntervalTimer could not register its hardware callback");
180 }
181 }
182}
183
184IntervalTimer::~IntervalTimer() {
185 if (m_pTimer) {
186 if (!m_pTimer->unregisterHandler(this)) {
187 FATAL("IntervalTimer could not drain its hardware callback");
188 }
189 m_pTimer = nullptr;
190 }
191}
192
193void IntervalTimer::setInterval(Time::Timestamp interval, Time::Timestamp* prevInterval) {
194 bool needsSignal = false;
195 {
196 LockGuard<Spinlock> guard(m_Lock);
197 needsSignal = advanceTimeLocked(absoluteTotal());
198
199 if (prevInterval) {
200 *prevInterval = m_Interval;
201 }
202 m_Interval = interval;
203 armHardwareLocked();
204 }
205 if (needsSignal) {
206 signal();
207 }
208}
209
210void IntervalTimer::setTimerValue(Time::Timestamp value, Time::Timestamp* prevValue) {
211 bool needsSignal = false;
212 {
213 LockGuard<Spinlock> guard(m_Lock);
214 needsSignal = advanceTimeLocked(absoluteTotal());
215
216 if (prevValue) {
217 *prevValue = m_Value;
218 }
219 m_Value = value;
220 setArmedLocked(m_Value > 0);
221 armHardwareLocked();
222 }
223 if (needsSignal) {
224 signal();
225 }
226}
227
228void IntervalTimer::setIntervalAndValue(Time::Timestamp interval, Time::Timestamp value,
229 Time::Timestamp* prevInterval, Time::Timestamp* prevValue) {
230 bool needsSignal = false;
231 {
232 LockGuard<Spinlock> guard(m_Lock);
233 needsSignal = advanceTimeLocked(absoluteTotal());
234
235 if (prevInterval) {
236 *prevInterval = m_Interval;
237 }
238
239 if (prevValue) {
240 *prevValue = m_Value;
241 }
242
243 m_Interval = interval;
244 m_Value = value;
245 setArmedLocked(m_Value > 0);
246 armHardwareLocked();
247 }
248 if (needsSignal) {
249 signal();
250 }
251}
252
254 LockGuard<Spinlock> guard(m_Lock);
255 const Time::Timestamp current = absoluteTotal();
256 if (current > m_LastTotal) {
257 m_LastTotal = current;
258 }
259 m_Value = 0;
260 m_Interval = 0;
261 setArmedLocked(false);
262 armHardwareLocked();
263}
264
265void IntervalTimer::getIntervalAndValue(Time::Timestamp& interval, Time::Timestamp& value) {
266 bool needsSignal = false;
267 {
268 LockGuard<Spinlock> guard(m_Lock);
269 needsSignal = advanceTimeLocked(absoluteTotal());
270
271 interval = m_Interval;
272 value = m_Value;
273 armHardwareLocked();
274 }
275 if (needsSignal) {
276 signal();
277 }
278}
279
280void IntervalTimer::consumeCpuTime(Time::Timestamp absoluteTotal) {
281 if (m_Mode == Hardware) {
282 return;
283 }
284
285 bool needsSignal = false;
286 {
287 LockGuard<Spinlock> guard(m_Lock);
288 needsSignal = advanceTimeLocked(absoluteTotal);
289 }
290
291 if (needsSignal) {
292 signal();
293 }
294}
295
296Time::Timestamp IntervalTimer::absoluteTotal() const {
297 if (m_Mode == Hardware) {
298 return Time::getTicks();
299 }
300 if (m_Mode == Virtual) {
301 return m_Process->getUserTime();
302 }
303 if (m_Mode == Profile) {
304 return m_Process->getUserTime() + m_Process->getKernelTime();
305 }
306 return 0;
307}
308
309bool IntervalTimer::advanceTimeLocked(Time::Timestamp absoluteTotal) {
311 PosixIntervalTimerState::consumeAbsolute(m_Value, m_Interval, m_Armed, m_LastTotal,
312 absoluteTotal);
313 m_Value = result.timer.value;
314 setArmedLocked(result.timer.armed);
315 m_LastTotal = result.baseline;
316 return result.timer.expired;
317}
318
319void IntervalTimer::armHardwareLocked() {
320 if (m_Mode != Hardware || !m_pTimer || !m_pTimer->supportsDeadlines()) {
321 return;
322 }
323 const Time::Timestamp maximum = Time::Infinity - 1;
324 const Time::Timestamp deadline =
325 !m_Armed ? 0 : (m_Value > maximum - m_LastTotal ? maximum : m_LastTotal + m_Value);
326 if (!m_pTimer->armHandler(this, deadline)) {
327 FATAL("IntervalTimer could not arm its hardware callback");
328 }
329}
330
331void IntervalTimer::setArmedLocked(bool armed) {
332 if (m_Armed == armed) {
333 return;
334 }
335 m_Armed = armed;
336 if (m_Mode != Hardware) {
337 m_Process->setTimeAccountingReportInterest(size_t(1) << m_Mode, armed);
338 }
339}
340
341Time::Timestamp IntervalTimer::getInterval() const {
342 return m_Interval;
343}
344
345Time::Timestamp IntervalTimer::getValue() const {
346 return m_Value;
347}
348
349void IntervalTimer::timer(uint64_t delta) {
350 (void)delta;
351 if (m_Mode != Hardware) {
352 return;
353 }
354
355 bool needsSignal = false;
356 {
357 LockGuard<Spinlock> guard(m_Lock);
358
359 if (!m_Armed) {
360 // Disarmed - ignore the timer event.
361 return;
362 }
363
364 needsSignal = advanceTimeLocked(absoluteTotal());
365 armHardwareLocked();
366 }
367
368 if (needsSignal) {
369 signal();
370 }
371}
372
374 int signal = -1;
375 switch (m_Mode) {
376 case Hardware:
377 signal = SIGALRM;
378 break;
379 case Virtual:
380 signal = SIGVTALRM;
381 break;
382 case Profile:
383 signal = SIGPROF;
384 break;
385 }
386
389 if (!Scheduler::instance().acquireProcess(process, m_Process)) {
390 return;
391 }
392 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(process->getSubsystem());
394 const bool targetAcquired = process->acquireProcessSignalThread(target);
395 if (!pSubsystem || !targetAcquired) {
396 return;
397 }
398
399 // Don't yield in the middle of the timer handler
400 pSubsystem->sendSignal(target.get(), signal, false, true);
401}
IntervalTimer(PosixProcess *pProcess, Mode mode=Hardware)
void setInterval(Time::Timestamp interval, Time::Timestamp *prevInterval=nullptr)
@ Virtual
CPU time in user mode only.
@ Hardware
Hardware-backed timer (wall time).
@ Profile
CPU time in user and system.
void setTimerValue(Time::Timestamp value, Time::Timestamp *prevValue=nullptr)
Set the current value of the timer.
void consumeCpuTime(Time::Timestamp absoluteTotal)
virtual void timer(uint64_t delta)
void setIntervalAndValue(Time::Timestamp interval, Time::Timestamp value, Time::Timestamp *prevInterval=nullptr, Time::Timestamp *prevValue=nullptr)
Set both interval and value atomically.
virtual Timer * getTimer()=0
virtual void processTerminated()
virtual void reportTimesUpdated(Time::Timestamp userTotal, Time::Timestamp total)
virtual void sendSignal(Thread *pThread, int signal, bool yield=true, bool processDirected=false)
MUST_USE_RESULT bool acquireProcessSignalThread(ThreadLease &lease)
Definition Process.cc:1407
void publish()
Definition Process.cc:944
Time::Timestamp getUserTime() const
Definition Process.h:829
void prepareForDestruction()
Definition Process.cc:1029
void setTimeAccountingReportInterest(size_t interest, bool enabled)
Definition Process.cc:844
void enableTimeAccountingReports(size_t initialInterest=~size_t(0))
Definition Process.cc:839
static Scheduler & instance()
Definition Scheduler.h:96
virtual bool kill(KillReason killReason, Thread *pThread=0)=0
virtual bool supportsDeadlines() const
virtual bool armHandler(TimerHandler *, uint64_t)