The Pedigree Project 0.1
Process.h
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#ifndef PROCESS_H
21#define PROCESS_H
22#include "pedigree/kernel/Atomic.h"
23#include "pedigree/kernel/Spinlock.h"
24#include "pedigree/kernel/Subsystem.h"
25#include "pedigree/kernel/compiler.h"
26#include "pedigree/kernel/process/DeferredTimeAccounting.h"
27#include "pedigree/kernel/process/FilesystemContext.h"
28#include "pedigree/kernel/process/FilesystemCredentials.h"
29#include "pedigree/kernel/process/Mutex.h"
30#include "pedigree/kernel/process/OperationBarrier.h"
31#include "pedigree/kernel/process/TerminationDeferral.h"
32#include "pedigree/kernel/process/Thread.h"
33#include "pedigree/kernel/process/Uninterruptible.h"
34#include "pedigree/kernel/process/WaitQueue.h"
35#include "pedigree/kernel/processor/types.h"
36#include "pedigree/kernel/time/Time.h"
37#include "pedigree/kernel/utilities/List.h"
38#include "pedigree/kernel/utilities/MemoryAllocator.h"
39#include "pedigree/kernel/utilities/SharedPointer.h"
40#include "pedigree/kernel/utilities/StaticString.h"
41#include "pedigree/kernel/utilities/Vector.h"
42#include "pedigree/kernel/utilities/new"
43
44#include <config.h>
45
47class File;
48class User;
49class Group;
50class DynamicLinker;
51class ZombieProcess;
52class ZombieQueue;
53class Scheduler;
54
55class Process;
56
58class EXPORTED_PUBLIC UserspacePidNamespace {
59 public:
61 : m_Parent(parent), m_NextPid(0) {}
62 size_t allocate() {
63 return m_NextPid += 1;
64 }
65 const SharedPointer<UserspacePidNamespace>& parent() const {
66 return m_Parent;
67 }
68 bool dead() const {
69 return __atomic_load_n(&m_Dead, __ATOMIC_ACQUIRE);
70 }
71 void close() {
72 __atomic_store_n(&m_Dead, true, __ATOMIC_RELEASE);
73 }
74 Process* init() const {
75 return __atomic_load_n(&m_Init, __ATOMIC_ACQUIRE);
76 }
77 void setInit(Process* process) {
78 __atomic_store_n(&m_Init, process, __ATOMIC_RELEASE);
79 }
80 size_t depth() const {
81 return m_Parent ? m_Parent->depth() + 1 : 1;
82 }
83
84 private:
86 Atomic<size_t> m_NextPid;
87 Process* m_Init = nullptr;
88 bool m_Dead = false;
89};
90
92class EXPORTED_PUBLIC UserspacePid {
93 public:
95 size_t id(const UserspacePidNamespace* space = nullptr) const;
96 const SharedPointer<UserspacePidNamespace>& space() const {
97 return m_Namespace;
98 }
99
100 private:
102 Vector<size_t> m_Ids;
103};
104
109class EXPORTED_PUBLIC Process {
110 friend class PerProcessorScheduler;
111 friend class Scheduler;
112 friend class Thread;
113 friend class ZombieProcess;
114 friend class ZombieQueue;
115
116 public:
118 class EXPORTED_PUBLIC ExecScope {
119 public:
120 explicit ExecScope(Process& process, bool active = true);
121 ~ExecScope();
122 explicit operator bool() const {
123 return m_bAdmitted;
124 }
125 bool commit();
126 void adoptLeaderIdentity();
127
128 private:
129 ExecScope(const ExecScope&) = delete;
130 ExecScope& operator=(const ExecScope&) = delete;
131 Process* m_pProcess;
132 bool m_bAdmitted;
133 TerminationDeferral m_TerminationDeferral;
134 };
135
137 class EXPORTED_PUBLIC ThreadCreationScope {
138 public:
139 explicit ThreadCreationScope(Process& process);
141 explicit operator bool() const {
142 return m_pProcess != nullptr;
143 }
144
145 private:
147 ThreadCreationScope& operator=(const ThreadCreationScope&) = delete;
148 Process* m_pProcess;
149 TerminationDeferral m_TerminationDeferral;
150 };
151
156 class EXPORTED_PUBLIC ReaperClaim {
157 public:
158 ReaperClaim();
159 ReaperClaim(ReaperClaim&& other) noexcept;
160 ~ReaperClaim();
161
162 ReaperClaim& operator=(ReaperClaim&& other) noexcept;
163
164 explicit operator bool() const {
165 return m_pProcess != nullptr;
166 }
167
168 void publish();
169
170 private:
171 friend class Process;
172 explicit ReaperClaim(Process* process);
173
174 ReaperClaim(const ReaperClaim&) = delete;
175 ReaperClaim& operator=(const ReaperClaim&) = delete;
176
177 Process* m_pProcess;
178 TerminationDeferral m_TerminationDeferral;
179 };
180
189 class EXPORTED_PUBLIC ThreadLease {
190 public:
191 ThreadLease();
192 ThreadLease(ThreadLease&& other) noexcept;
193 ~ThreadLease();
194
195 ThreadLease& operator=(ThreadLease&& other) noexcept;
196
197 Thread* get() const {
198 return m_pThread;
199 }
200
201 Thread* operator->() const {
202 return m_pThread;
203 }
204
205 explicit operator bool() const {
206 return m_pThread != nullptr;
207 }
208
209 void reset();
210
211 private:
212 friend class Process;
213
214 ThreadLease(Process* process, Thread* thread);
215 ThreadLease(const ThreadLease&) = delete;
216 ThreadLease& operator=(const ThreadLease&) = delete;
217
218 Process* m_pProcess;
219 Thread* m_pThread;
220 TerminationDeferral m_TerminationDeferral;
221 };
222
224
226 class EXPORTED_PUBLIC FileContextLease {
227 public:
230
231 File* get() const {
232 return m_pFile;
233 }
234 SharedPointer<ControllingTerminal> context() const {
235 return m_Context;
236 }
237
238 File* operator->() const {
239 return m_pFile;
240 }
241
242 explicit operator bool() const {
243 return m_pFile != nullptr;
244 }
245
246 void reset();
247
248 private:
249 friend class Process;
250
251 FileContextLease(const FileContextLease&) = delete;
252 FileContextLease& operator=(const FileContextLease&) = delete;
254 FileContextLease& operator=(FileContextLease&&) = delete;
255
256 File* m_pFile;
257 TerminationDeferral m_TerminationDeferral;
259 };
260
265 class EXPORTED_PUBLIC TerminalOwnerReservation {
266 public:
270
271 TerminalOwnerReservation& operator=(TerminalOwnerReservation&& other) noexcept;
272
273 explicit operator bool() const {
274 return m_pProcess != nullptr;
275 }
276
278 void install(Thread* owner);
279
280 private:
281 friend class Process;
282
284 TerminalOwnerReservation& operator=(const TerminalOwnerReservation&) = delete;
285
286 Process* m_pProcess;
287 TerminationDeferral m_TerminationDeferral;
288 };
289
296 enum ProcessType { Stock, Posix };
297
304 Active,
305 Suspended,
306 Terminating,
307 Terminated,
309 };
310
311#if PEDIGREE_BENCHMARK_SYSCALL_TRACE
312 void setBenchmarkSyscallTrace(bool enabled) {
313 __atomic_store_n(&m_BenchmarkSyscallTrace, enabled, __ATOMIC_RELEASE);
314 }
315
316 bool benchmarkSyscallTraceEnabled() const {
317 return __atomic_load_n(&m_BenchmarkSyscallTrace, __ATOMIC_ACQUIRE);
318 }
319#endif
320
321#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
322 static constexpr size_t SyscallTimingRawSlotCount = 512;
323 static constexpr size_t SyscallTimingOverflowSlot = SyscallTimingRawSlotCount;
324 static constexpr size_t SyscallTimingSlotCount = SyscallTimingRawSlotCount + 1;
325
326 struct SyscallTimingEntry {
327 uint64_t calls;
328 uint64_t kernelNanoseconds;
329 };
330
331 static size_t syscallTimingSlot(size_t rawNumber) {
332 return rawNumber < SyscallTimingRawSlotCount ? rawNumber : SyscallTimingOverflowSlot;
333 }
334
335 void setBenchmarkSyscallTiming(bool enabled) {
336 __atomic_store_n(&m_BenchmarkSyscallTiming, enabled, __ATOMIC_RELEASE);
337 }
338
339 bool benchmarkSyscallTimingEnabled() const {
340 return __atomic_load_n(&m_BenchmarkSyscallTiming, __ATOMIC_ACQUIRE);
341 }
342
343 void recordSyscallTimingCall(size_t slot) {
344 __atomic_fetch_add(&m_SyscallTimingCalls[slot], static_cast<uint64_t>(1), __ATOMIC_RELAXED);
345 }
346
347 void recordSyscallTimingKernel(size_t slot, Time::Timestamp elapsed) {
348 __atomic_fetch_add(&m_SyscallTimingKernelNanoseconds[slot], elapsed, __ATOMIC_RELAXED);
349 }
350
351 void getSyscallTimingEntry(size_t slot, SyscallTimingEntry& result) const {
352 result.calls = __atomic_load_n(&m_SyscallTimingCalls[slot], __ATOMIC_ACQUIRE);
353 result.kernelNanoseconds =
354 __atomic_load_n(&m_SyscallTimingKernelNanoseconds[slot], __ATOMIC_ACQUIRE);
355 }
356#endif
357
358#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
359 enum BenchmarkVmCounter : size_t {
360 VmMmapCalls,
361 VmMmapAnonymousCalls,
362 VmMmapFileCalls,
363 VmMmapPages,
364 VmMmapLength1,
365 VmMmapLength2To3,
366 VmMmapLength4To15,
367 VmMmapLength16To63,
368 VmMmapLength64To255,
369 VmMmapLength256Plus,
370 VmPublishCalls,
371 VmPublishObjectCount,
372 VmPublishOverlapProbeVisits,
373 VmPublishOverlapHits,
374 VmPublishCommitRetries,
375 VmReservationSnapshots,
376 VmReservationExtents,
377 VmReservationScratchAllocations,
378 VmMunmapCalls,
379 VmMunmapPages,
380 VmMunmapLength1,
381 VmMunmapLength2To3,
382 VmMunmapLength4To15,
383 VmMunmapLength16To63,
384 VmMunmapLength64To255,
385 VmMunmapLength256Plus,
386 VmRemoveCalls,
387 VmRemoveObjectCount,
388 VmRemoveObjectVisits,
389 VmRemoveSliceCalls,
390 VmRemoveAffectedObjects,
391 VmAllowsCalls,
392 VmAllowsObjectCount,
393 VmAllowsObjectVisits,
394 VmFaultInRangeCalls,
395 VmFaultInRangePages,
396 VmFaultInObjectVisits,
397 VmFaultInPresent,
398 VmFaultInCopyOnWrite,
399 VmFaultInTrap,
400 VmFaultCalls,
401 VmFaultObjectCount,
402 VmFaultObjectVisits,
403 VmFaultResolved,
404 VmFaultBacking,
405 VmFaultUnhandled,
406 VmGuardEntries,
407 VmGuardRecursiveEntries,
408 VmDiscardTrackedPages,
409 VmDiscardMappedPages,
410 VmTableRetirementScans,
411 VmDetachPteEntries,
412 VmDetachPdeEntries,
413 VmDetachPdptEntries,
414 VmDetachTables,
415 VmInvalidationActive,
416 VmInvalidationInactive,
417 BenchmarkVmCounterCount,
418 };
419
420 void setBenchmarkVmDiagnostics(bool enabled) {
421 __atomic_store_n(&m_BenchmarkVmDiagnostics, enabled, __ATOMIC_RELEASE);
422 }
423
424 bool benchmarkVmDiagnosticsEnabled() const {
425 return __atomic_load_n(&m_BenchmarkVmDiagnostics, __ATOMIC_ACQUIRE);
426 }
427
428 void recordBenchmarkVmCounter(BenchmarkVmCounter counter, uint64_t amount = 1) {
429 if (benchmarkVmDiagnosticsEnabled() && amount) {
430 __atomic_fetch_add(&m_BenchmarkVmCounters[counter], amount, __ATOMIC_RELAXED);
431 }
432 }
433
434 uint64_t getBenchmarkVmCounter(size_t counter) const {
435 return __atomic_load_n(&m_BenchmarkVmCounters[counter], __ATOMIC_ACQUIRE);
436 }
437#endif
438
440 Process();
441
449 Process(Process* pParent, bool bCopyOnWrite = true);
450
452 virtual ~Process();
453
456 size_t addThread(Thread* pThread);
458 void threadExiting(Thread* pThread);
460 void transferExecProcessSignals(Thread* pThread);
462 void removeThread(Thread* pThread);
463
465 size_t getNumThreads();
470 MUST_USE_RESULT bool acquireThread(ThreadLease& lease, size_t n);
471
473 MUST_USE_RESULT bool acquireProcessSignalThread(ThreadLease& lease);
474
479 MUST_USE_RESULT bool acquireThreadById(ThreadLease& lease, size_t id);
480
481 MUST_USE_RESULT bool acquireThreadByTaskId(ThreadLease& lease, size_t id);
482 MUST_USE_RESULT bool acquireThreadByUserspaceId(ThreadLease& lease, size_t id,
483 const UserspacePidNamespace* space);
484
489 MUST_USE_RESULT bool acquireThread(ThreadLease& lease, Thread* expected);
490
496 TerminalOwnerReservation reserveTerminalOwner();
497
499 size_t getId() {
500 return m_Id;
501 }
502
504 size_t getUserspaceId() const {
505 return m_UserspacePid ? m_UserspacePid->id() : 0;
506 }
507
508 size_t getUserspaceId(const UserspacePidNamespace* space) const {
509 return m_UserspacePid ? m_UserspacePid->id(space) : 0;
510 }
511 SharedPointer<UserspacePidNamespace> pidNamespace() const {
512 return m_UserspaceNamespace;
513 }
514 SharedPointer<UserspacePid> pidIdentity() const {
515 return m_UserspacePid;
516 }
517 SharedPointer<UserspacePidNamespace> pidNamespaceForChildren();
518 static SharedPointer<UserspacePidNamespace> rootPidNamespace();
519 bool createPidNamespace();
520 bool unsharePidNamespace();
521 bool unsharePidNamespace(const SharedPointer<UserspacePidNamespace>& prepared);
522 bool pidNamespaceReady() const;
523
526 return str;
527 }
528
531 return m_pAddressSpace;
532 }
533
534 class EXPORTED_PUBLIC VforkCompletion {
535 public:
536 void wait();
537 void complete();
538
539 private:
540 WaitQueue m_Waiters;
541 bool m_Complete = false;
542 };
543
546 return m_pVforkOwner ? m_pVforkOwner : this;
547 }
548 bool isVforkChild() const {
549 return m_pVforkOwner != nullptr;
550 }
551 void borrowVforkAddressSpace(Process& parent, const SharedPointer<VforkCompletion>& completion);
553 void releaseVforkAddressSpace();
554
556 void setExitStatus(int code) {
557 m_ExitStatus = code;
558 }
561 return m_ExitStatus;
562 }
563
564 enum class ChildTransitionKind {
565 None,
566 Stopped,
567 Continued,
568 };
569
571 ChildTransition() : kind(ChildTransitionKind::None), stopSignal(0) {}
572
573 ChildTransitionKind kind;
574 int stopSignal;
575 };
576
583 void reap();
584
586 bool prepareThreadExit();
587
593 bool beginTermination(int code = 0, Subsystem::ExitCause cause = Subsystem::ExitCause::Normal);
594
599 bool quiesceTermination();
600
602 void finishTermination(bool notifyParent = false) NORETURN;
603
605 ReaperClaim tryClaimReaper();
606
608 void kill() NORETURN;
610 void suspend(int stopSignal = 0);
612 void suspendIfContinuationEpoch(int stopSignal, size_t continuationEpoch);
614 void resume();
615
617 size_t getContinuationEpoch();
618
620 Process* getParent() {
621 return __atomic_load_n(&m_pParent, __ATOMIC_ACQUIRE);
622 }
623
624 enum class FilesystemContextMode { Inherit, Deferred };
625
626 FilesystemContextRef acquireFilesystemContext() const;
628 MUST_USE_RESULT bool installFilesystemContext(FilesystemContextOwner&& context);
629 bool replaceFilesystemContext(FilesystemContextOwner&& replacement,
630 const FilesystemContextRef& expected);
631 bool filesystemContextReady() const;
632 void releaseFilesystemContext();
633
634 class EXPORTED_PUBLIC ControllingTerminal {
635 public:
636 virtual ~ControllingTerminal() = default;
637 virtual File* file() const = 0;
638 };
639
640 SharedPointer<ControllingTerminal> acquireCttyContext() const;
641 MUST_USE_RESULT File* acquireCtty(FileContextLease& lease) const;
642 void setCttyContext(const SharedPointer<ControllingTerminal>& context);
644 MUST_USE_RESULT bool setCtty(File* file);
645
646 enum class UserRegion { Normal, Dynamic };
647
649 UserReservationSnapshot() : normal(false), dynamic(false), generation(0) {}
650 MemoryAllocator normal;
651 MemoryAllocator dynamic;
652 uint64_t generation;
653 };
654
655 bool snapshotUserReservations(UserReservationSnapshot& result);
657 bool commitUserReservations(uint64_t expectedGeneration, UserReservationSnapshot& replacement);
658 bool allocateUserRange(UserRegion region, size_t length, uintptr_t& address);
659 bool allocateSpecificUserRange(UserRegion region, uintptr_t address, size_t length);
660 void freeUserRange(UserRegion region, uintptr_t address, size_t length);
661 void resetUserReservations();
662
663 virtual bool snapshotFilesystemCredentials(const Thread* task, FilesystemCredentials& out) const;
664 static bool currentFilesystemCredentials(FilesystemCredentials& out);
665 void inheritFilesystemIds(Thread& child, const Thread* creator) const;
666 virtual bool installUserIdentity(User*, Group*, const uint32_t* groups, size_t count);
667
668 class EXPORTED_PUBLIC FilesystemAccessScope {
669 public:
670 explicit FilesystemAccessScope(const FilesystemCredentials& credentials);
672
673 private:
675 FilesystemAccessScope& operator=(const FilesystemAccessScope&) = delete;
676 Uninterruptible m_Events;
677 TerminationDeferral m_Termination;
678 FilesystemCredentials m_Credentials;
679 Thread* m_Thread;
680 const FilesystemCredentials* m_Previous;
681 };
682
684 User* getUser() const;
686 void setUser(User* pUser);
687
689 User* getEffectiveUser() const;
691 void setEffectiveUser(User* pUser);
692
694 Group* getGroup() const;
696 void setGroup(Group* pGroup);
697
699 Group* getEffectiveGroup() const;
700 void setEffectiveGroup(Group* pGroup);
701
704 virtual int64_t getUserId() const;
705 virtual int64_t getGroupId() const;
706 virtual int64_t getEffectiveUserId() const;
707 virtual int64_t getEffectiveGroupId() const;
708 virtual void getSupplementalGroupIds(Vector<int64_t>& vec) const;
709 virtual void setUserId(int64_t id);
710 virtual void setGroupId(int64_t id);
711 virtual void setEffectiveUserId(int64_t id);
712 virtual void setEffectiveGroupId(int64_t id);
713
714 void setLinker(DynamicLinker* pDl) {
715 m_pDynamicLinker = pDl;
716 }
717 DynamicLinker* getLinker() {
718 return m_pDynamicLinker;
719 }
720
721 void setSubsystem(Subsystem* pSubsystem) {
722 m_pSubsystem = pSubsystem;
723 m_pSubsystem->setProcess(this);
724 }
725 Subsystem* getSubsystem() {
726 return m_pSubsystem;
727 }
728
729 ProcessType getType() const {
730 return m_Type;
731 }
732
737 return m_ChildStateWaiters.acquire();
738 }
739
744 bool waitUntilTerminationReapable();
745
750 bool waitUntilTerminationReapableForTerminalCoordinator();
751
757 bool selectPendingChildTransition(bool includeStopped, bool includeContinued, bool consume,
758 ChildTransition& transition);
759
761 bool takePendingChildTransition(bool includeStopped, bool includeContinued,
762 ChildTransition& transition);
763
764 ProcessState getState() const {
765 return __atomic_load_n(&m_State, __ATOMIC_ACQUIRE);
766 }
767
768 bool isSuspended() {
769 return getState() == Suspended;
770 }
771
772 void markTerminating();
773
774#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
775 using TerminationElectionHook = void (*)(Process*, Thread*);
776 static void setTerminationElectionHook(TerminationElectionHook hook);
777
778 enum ExternalLeaseReleasePhase {
779 ExternalLeaseFinalReleaseUnlocked,
780 ExternalLeaseBeforeWaiterWake,
781 };
782 using ExternalLeaseReleaseHook = void (*)(Process*, ExternalLeaseReleasePhase);
783 static void setExternalLeaseReleaseHookForHostedTest(Process* target,
784 ExternalLeaseReleaseHook hook);
785
787 bool isTerminationReapableForHostedTest();
788
789 enum class OrphanPublicationPhase {
790 Preparing,
791 Published,
792 };
793 using OrphanPublicationHook = void (*)(Process*, OrphanPublicationPhase, bool interruptsEnabled,
794 bool processLockHeld);
795 static void setOrphanPublicationHook(OrphanPublicationHook hook);
796
798 void publishTimeAccountingForHostedTest(Time::Timestamp user, Time::Timestamp system);
799
801 void closeTimeAccountingForHostedTest();
802
803 bool timeAccountingPendingForHostedTest() const {
804 return m_DeferredTimeAccounting.pending();
805 }
806 size_t timeAccountingInterestForHostedTest() const {
807 return __atomic_load_n(&m_TimeAccountingReportInterest, __ATOMIC_ACQUIRE);
808 }
809#endif
810
811 void trackHeap(ssize_t nBytes) {
812 __atomic_fetch_add(&m_Metadata.heapUsage, nBytes, __ATOMIC_RELAXED);
813 }
814
815 void trackPages(ssize_t nVirtual, ssize_t nPhysical, ssize_t nShared) {
816 __atomic_fetch_add(&m_Metadata.virtualPages, nVirtual, __ATOMIC_RELAXED);
817 __atomic_fetch_add(&m_Metadata.physicalPages, nPhysical, __ATOMIC_RELAXED);
818 __atomic_fetch_add(&m_Metadata.sharedPages, nShared, __ATOMIC_RELAXED);
819 }
820
821 void resetCounts() {
822 __atomic_store_n(&m_Metadata.virtualPages, static_cast<ssize_t>(0), __ATOMIC_RELEASE);
823 __atomic_store_n(&m_Metadata.physicalPages, static_cast<ssize_t>(0), __ATOMIC_RELEASE);
824 __atomic_store_n(&m_Metadata.sharedPages, static_cast<ssize_t>(0), __ATOMIC_RELEASE);
825 __atomic_store_n(&m_Metadata.startTime, Time::getTimeNanoseconds(), __ATOMIC_RELEASE);
826 }
827
829 Time::Timestamp getUserTime() const {
830 return totalTime(CpuTimeMode::User);
831 }
832 Time::Timestamp getKernelTime() const {
833 return totalTime(CpuTimeMode::Kernel);
834 }
835 Time::Timestamp getReapedChildrenUserTime() const {
836 return __atomic_load_n(&m_Metadata.reapedChildrenUserTime, __ATOMIC_ACQUIRE);
837 }
838 Time::Timestamp getReapedChildrenKernelTime() const {
839 return __atomic_load_n(&m_Metadata.reapedChildrenKernelTime, __ATOMIC_ACQUIRE);
840 }
841
842#if PEDIGREE_SYSCALL_COUNTER
843 static constexpr size_t SyscallLatencyBucketCount = 16;
844
845 struct SyscallLatencySnapshot {
846 uint64_t buckets[SyscallLatencyBucketCount];
847 };
848
850 void recordSyscall() {
851 __atomic_fetch_add(&m_Metadata.syscallCount, static_cast<uint64_t>(1), __ATOMIC_RELAXED);
852 }
853
855 void recordSyscallDuration(Time::Timestamp duration) {
856 size_t bucket = 0;
857 Time::Timestamp limit = Time::Multiplier::Microsecond;
858 while (bucket + 1 < SyscallLatencyBucketCount && duration >= limit) {
859 ++bucket;
860 limit <<= 1;
861 }
862 __atomic_fetch_add(&m_Metadata.syscallLatencyBuckets[bucket], static_cast<uint64_t>(1),
863 __ATOMIC_RELAXED);
864 }
865
866 uint64_t getSyscallCount() const {
867 return __atomic_load_n(&m_Metadata.syscallCount, __ATOMIC_ACQUIRE);
868 }
869
870 uint64_t getReapedChildrenSyscallCount() const {
871 return __atomic_load_n(&m_Metadata.reapedChildrenSyscallCount, __ATOMIC_ACQUIRE);
872 }
873
874 void getSyscallLatencySnapshot(SyscallLatencySnapshot& snapshot) const {
875 for (size_t i = 0; i < SyscallLatencyBucketCount; ++i) {
876 snapshot.buckets[i] =
877 __atomic_load_n(&m_Metadata.syscallLatencyBuckets[i], __ATOMIC_ACQUIRE) +
878 __atomic_load_n(&m_Metadata.reapedChildrenSyscallLatencyBuckets[i], __ATOMIC_ACQUIRE);
879 }
880 }
881
882 void getReapedChildrenSyscallLatencySnapshot(SyscallLatencySnapshot& snapshot) const {
883 for (size_t i = 0; i < SyscallLatencyBucketCount; ++i) {
884 snapshot.buckets[i] =
885 __atomic_load_n(&m_Metadata.reapedChildrenSyscallLatencyBuckets[i], __ATOMIC_ACQUIRE);
886 }
887 }
888#endif
889
895 void accountReapedChild(const Process* child, Time::Timestamp& user, Time::Timestamp& kernel);
896
897 Time::Timestamp getStartTime() const {
898 return __atomic_load_n(&m_Metadata.startTime, __ATOMIC_ACQUIRE);
899 }
900
902 ssize_t getHeapUsage() const {
903 return __atomic_load_n(&m_Metadata.heapUsage, __ATOMIC_ACQUIRE);
904 }
905 ssize_t getVirtualPageCount() const {
906 return __atomic_load_n(&m_Metadata.virtualPages, __ATOMIC_ACQUIRE);
907 }
908 ssize_t getPhysicalPageCount() const {
909 return __atomic_load_n(&m_Metadata.physicalPages, __ATOMIC_ACQUIRE);
910 }
911 ssize_t getSharedPageCount() const {
912 return __atomic_load_n(&m_Metadata.sharedPages, __ATOMIC_ACQUIRE);
913 }
914
920 return m_bSharedAddressSpace;
921 }
922
927 static Process* getInit();
928
930 static void setInit(Process* pProcess);
931
932 protected:
933 mutable Spinlock m_CredentialLock;
934 static bool loadFilesystemIds(const Thread&, uint32_t& uid, uint32_t& gid);
935 static void publishFilesystemIds(Thread&, uint32_t uid, uint32_t gid);
936 void publishAccountIdentity(User*, Group*);
937
943
945 Process(DeferredPublication, Process* pParent, bool bCopyOnWrite = true,
946 FilesystemContextMode filesystemContext = FilesystemContextMode::Inherit,
947 bool emptyAddressSpace = false, ProcessType type = Stock);
948
950 void publish();
951
952#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
957 void makeOrphanBeforePublicationForHostedTest();
958#endif
959
966 void prepareForDestruction();
967
969 void enableTimeAccountingReports(size_t initialInterest = ~size_t(0));
970
972 void setTimeAccountingReportInterest(size_t interest, bool enabled);
973
974 private:
975 void finishTermination(bool abandonStack, bool notifyParent) NORETURN;
976
977 Process(const Process&);
978 Process& operator=(const Process&);
979
984 virtual void reportTimesUpdated(Time::Timestamp userTotal, Time::Timestamp total) {}
985
987 void drainDeferredTimeAccounting();
988
990 void closeDeferredTimeAccounting();
991
993 Time::Timestamp totalTime(CpuTimeMode mode) const;
994
995 ALWAYS_INLINE void reportTimeAccounting(Time::Timestamp elapsed) {
996 // Most processes have no armed CPU-time timer. Keep that path free of
997 // worker publication and its lifecycle-admission load.
998 if (__atomic_load_n(&m_TimeAccountingReportInterest, __ATOMIC_ACQUIRE) &&
999 __atomic_load_n(&m_bTimeAccountingReportsEnabled, __ATOMIC_ACQUIRE)) {
1000 queueTimeAccountingReport(elapsed);
1001 }
1002 }
1003
1004 void queueTimeAccountingReport(Time::Timestamp elapsed);
1005
1007 virtual void processTerminated() {}
1008
1020 size_t m_Id;
1025 SharedPointer<UserspacePidNamespace> m_ChildrenPidNamespace;
1038 VirtualAddressSpace* m_pVforkPrivateAddressSpace = nullptr;
1039 Process* m_pVforkOwner = nullptr;
1040 SharedPointer<VforkCompletion> m_VforkCompletion;
1045 FilesystemContextOwner m_FilesystemContext;
1046 bool m_bFilesystemContextReady;
1059 Spinlock m_UserReservationLock;
1060 uint64_t m_UserReservationGeneration;
1061
1062#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
1063 bool m_BenchmarkSyscallTiming = false;
1064 uint64_t m_SyscallTimingCalls[SyscallTimingSlotCount] = {};
1065 uint64_t m_SyscallTimingKernelNanoseconds[SyscallTimingSlotCount] = {};
1066#endif
1067
1068#if PEDIGREE_BENCHMARK_SYSCALL_TRACE
1069 bool m_BenchmarkSyscallTrace = false;
1070#endif
1071
1072#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1073 bool m_BenchmarkVmDiagnostics = false;
1074 uint64_t m_BenchmarkVmCounters[BenchmarkVmCounterCount] = {};
1075#endif
1076
1079 User* m_pUser;
1086
1089
1092
1095
1098
1101
1104
1107
1110
1113
1119
1122
1125
1128
1131
1134
1137
1138 // Construction selects the actual class, independently of the parent's type.
1139 const ProcessType m_Type;
1140
1146 bool transitionState(ProcessState expected, ProcessState desired);
1147
1149 void suspendInternal(int stopSignal, bool checkContinuationEpoch, size_t continuationEpoch);
1150
1152 void transitionToTerminating();
1153
1156
1159
1162
1165
1167 Thread* m_pExecOwner = nullptr;
1168 bool m_bExecCommitted = false;
1169 bool m_bExecExitForwarded = false;
1170 size_t m_nThreadCreations = 0;
1171 WaitQueue m_ExecWaiters;
1172
1175
1178
1181
1184
1187
1190
1193
1194 enum ReaperState {
1195 ReaperUnclaimed,
1196 ReaperClaimed,
1197 ReaperPublished,
1198 };
1199
1202
1205
1212
1218 bool terminatingThreadReapable(Thread* pThread, bool& wakeOwner);
1219
1221 void publishTerminationStatus(bool notifyParent);
1222
1224 void publishTerminationReapable();
1225
1227 void publishReaperClaim();
1228
1230 bool beginThreadJoin();
1231
1233 void endThreadJoin();
1234
1236 bool beginExternalLease();
1237
1239 void endExternalLease();
1240
1242 void closeExternalLeaseAdmission();
1243
1245 void drainExternalLeases();
1246
1248 void releaseThreadLease(Thread* thread);
1249
1251 void installTerminalOwner(Thread* owner);
1252
1255#if PEDIGREE_SYSCALL_COUNTER
1257 : heapUsage(0),
1258 virtualPages(0),
1259 physicalPages(0),
1260 sharedPages(0),
1261 userTime(0),
1262 kernelTime(0),
1263 reapedChildrenUserTime(0),
1264 reapedChildrenKernelTime(0),
1265 syscallCount(0),
1266 reapedChildrenSyscallCount(0),
1267 syscallLatencyBuckets{},
1268 reapedChildrenSyscallLatencyBuckets{},
1269 startTime(0) {}
1270#else
1272 : heapUsage(0),
1273 virtualPages(0),
1274 physicalPages(0),
1275 sharedPages(0),
1276 userTime(0),
1277 kernelTime(0),
1278 reapedChildrenUserTime(0),
1279 reapedChildrenKernelTime(0),
1280 startTime(0) {}
1281#endif
1282
1284 ssize_t heapUsage;
1292
1294 Time::Timestamp userTime;
1295 Time::Timestamp kernelTime;
1297 Time::Timestamp reapedChildrenUserTime;
1300
1301#if PEDIGREE_SYSCALL_COUNTER
1303 uint64_t syscallCount;
1305 uint64_t reapedChildrenSyscallCount;
1307 uint64_t syscallLatencyBuckets[SyscallLatencyBucketCount];
1309 uint64_t reapedChildrenSyscallLatencyBuckets[SyscallLatencyBucketCount];
1310#endif
1311
1313 Time::Timestamp startTime;
1314 } m_Metadata;
1315
1318
1321
1324
1327
1328 size_t m_TimeAccountingReportInterest;
1329
1332
1335
1336#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
1337 static TerminationElectionHook m_TerminationElectionHook;
1338 static ExternalLeaseReleaseHook m_ExternalLeaseReleaseHook;
1339 static Process* m_ExternalLeaseReleaseTarget;
1340 static OrphanPublicationHook m_OrphanPublicationHook;
1341#endif
1342};
1343
1344#endif
Definition File.h:75
Definition Group.h:32
Definition Mutex.h:56
Group * m_pGroup
Definition Process.h:1081
virtual void reportTimesUpdated(Time::Timestamp userTotal, Time::Timestamp total)
Definition Process.h:984
size_t getUserspaceId() const
Definition Process.h:504
void setExitStatus(int code)
Definition Process.h:556
ProcessState
Definition Process.h:303
@ Reaped
Terminal wait status is visible; the owner may still be on-stack.
Definition Process.h:308
ssize_t getHeapUsage() const
Definition Process.h:902
FilesystemCredentials m_NativeFilesystemCredentials
Definition Process.h:1078
bool m_bTerminalOwnerReserved
Definition Process.h:1180
Process * m_pParent
Definition Process.h:1033
size_t getId()
Definition Process.h:499
Subsystem * m_pSubsystem
Definition Process.h:1091
virtual void processTerminated()
Definition Process.h:1007
LargeStaticString str
Definition Process.h:1029
Group * m_pEffectiveGroup
Definition Process.h:1085
SharedPointer< UserspacePidNamespace > m_UserspaceNamespace
Definition Process.h:1022
int getExitStatus()
Definition Process.h:560
bool m_bPublished
Definition Process.h:1158
bool m_bUnregistered
Definition Process.h:1161
VirtualAddressSpace * getAddressSpace()
Definition Process.h:530
size_t m_nTerminationParticipants
Definition Process.h:1174
size_t m_nThreadJoinOperations
Definition Process.h:1109
bool m_bExternalLeaseAdmissionClosed
Definition Process.h:1127
bool hasSharedAddressSpace() const
Definition Process.h:919
WaitQueue::Guard acquireChildStateWait()
Definition Process.h:736
ProcessType
Definition Process.h:296
bool m_bTerminationReapable
Definition Process.h:1192
bool m_bSharedAddressSpace
Definition Process.h:1331
size_t m_ReaperState
Definition Process.h:1201
Atomic< size_t > m_NextTid
Definition Process.h:1016
Thread * m_pReservedTerminalOwner
Definition Process.h:1183
static Process * m_pInitProcess
Definition Process.h:1334
int m_ExitStatus
Definition Process.h:1042
WaitQueue m_ExternalLeaseWaiters
Definition Process.h:1121
OperationBarrier m_DeferredThreadReaps
Definition Process.h:1323
DynamicLinker * m_pDynamicLinker
Definition Process.h:1088
Spinlock m_ExternalLeaseLock
Definition Process.h:1118
VirtualAddressSpace * m_pAddressSpace
Definition Process.h:1037
bool m_bTerminationRendezvousStarted
Definition Process.h:1177
OperationBarrier m_TimeAccountingReports
Definition Process.h:1320
LargeStaticString & description()
Definition Process.h:525
User * m_pEffectiveUser
Definition Process.h:1083
Spinlock m_Lock
Definition Process.h:1204
bool m_bDestroying
Definition Process.h:1155
WaitQueue m_ThreadJoinWaiters
Definition Process.h:1106
Time::Timestamp getUserTime() const
Definition Process.h:829
Process * addressSpaceOwner()
Definition Process.h:545
bool m_bTerminationCleanupStarted
Definition Process.h:1186
bool m_bTimeAccountingReportsEnabled
Definition Process.h:1326
DeferredTimeAccounting m_DeferredTimeAccounting
Definition Process.h:1317
size_t m_Id
Definition Process.h:1020
Mutex m_FilesystemContextLock
Definition Process.h:1044
size_t m_nExternalLeases
Definition Process.h:1124
bool m_bTerminationSealed
Definition Process.h:1189
WaitQueue m_SuspensionWaiters
Definition Process.h:1100
bool m_bExternalLeaseReleaseInProgress
Definition Process.h:1130
SharedPointer< ControllingTerminal > m_Ctty
Definition Process.h:1050
ChildTransition m_PendingChildTransition
Definition Process.h:1133
MemoryAllocator m_DynamicSpaceAllocator
Definition Process.h:1058
MemoryAllocator m_SpaceAllocator
Definition Process.h:1054
Thread * m_pTerminatingThread
Definition Process.h:1164
WaitQueue m_ChildStateWaiters
Definition Process.h:1094
bool m_bThreadJoinAdmissionClosed
Definition Process.h:1112
ProcessState m_State
Definition Process.h:1136
WaitQueue m_TerminationWaiters
Definition Process.h:1097
Vector< Thread * > m_Threads
Definition Process.h:1012
Spinlock m_TimeAccountingLock
Definition Process.h:1211
SharedPointer< UserspacePid > m_UserspacePid
Definition Process.h:1024
size_t m_ContinuationEpoch
Definition Process.h:1103
This class manages how processes and threads are scheduled across processors.
Definition Scheduler.h:50
virtual void setProcess(Process *p)
Definition Subsystem.h:156
Definition User.h:32
A vector / dynamic array.
Definition Vector.h:33
Special wrapper object for Process.
Definition ZombieQueue.h:38
ssize_t physicalPages
Physical address space consumed, barring that which is shared.
Definition Process.h:1289
ssize_t sharedPages
Shared pages consumed.
Definition Process.h:1291
ssize_t heapUsage
Bytes used in the kernel heap by this process.
Definition Process.h:1284
Time::Timestamp reapedChildrenUserTime
Time spent in userspace by children this process has reaped.
Definition Process.h:1297
Time::Timestamp userTime
CPU time retained after threads leave the process topology.
Definition Process.h:1294
Time::Timestamp startTime
Time at which process started.
Definition Process.h:1313
Time::Timestamp reapedChildrenKernelTime
Time spent in the kernel by children this process has reaped.
Definition Process.h:1299