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/PerCpuTimeAccounting.h"
32#include "pedigree/kernel/process/TerminationDeferral.h"
33#include "pedigree/kernel/process/Thread.h"
34#include "pedigree/kernel/process/Uninterruptible.h"
35#include "pedigree/kernel/process/WaitQueue.h"
36#include "pedigree/kernel/processor/types.h"
37#include "pedigree/kernel/time/Time.h"
38#include "pedigree/kernel/utilities/List.h"
39#include "pedigree/kernel/utilities/MemoryAllocator.h"
40#include "pedigree/kernel/utilities/SharedPointer.h"
41#include "pedigree/kernel/utilities/StaticString.h"
42#include "pedigree/kernel/utilities/Vector.h"
43#include "pedigree/kernel/utilities/new"
44
45#include <config.h>
46
48class File;
49class User;
50class Group;
51class DynamicLinker;
52class ZombieProcess;
53class ZombieQueue;
54class Scheduler;
55
57class EXPORTED_PUBLIC UserspacePidNamespace {
58 public:
59 UserspacePidNamespace() : m_NextPid(0) {}
60
61 size_t allocate() {
62 return m_NextPid += 1;
63 }
64
65 private:
66 Atomic<size_t> m_NextPid;
67};
68
73class EXPORTED_PUBLIC Process {
74 friend class PerProcessorScheduler;
75 friend class Scheduler;
76 friend class Thread;
77 friend class ZombieProcess;
78 friend class ZombieQueue;
79
80 public:
82 class EXPORTED_PUBLIC ExecScope {
83 public:
84 explicit ExecScope(Process& process, bool active = true);
85 ~ExecScope();
86 explicit operator bool() const {
87 return m_bAdmitted;
88 }
89 bool commit();
90 void adoptLeaderIdentity();
91
92 private:
93 ExecScope(const ExecScope&) = delete;
94 ExecScope& operator=(const ExecScope&) = delete;
95 Process* m_pProcess;
96 bool m_bAdmitted;
97 TerminationDeferral m_TerminationDeferral;
98 };
99
101 class EXPORTED_PUBLIC ThreadCreationScope {
102 public:
103 explicit ThreadCreationScope(Process& process);
105 explicit operator bool() const {
106 return m_pProcess != nullptr;
107 }
108
109 private:
111 ThreadCreationScope& operator=(const ThreadCreationScope&) = delete;
112 Process* m_pProcess;
113 TerminationDeferral m_TerminationDeferral;
114 };
115
120 class EXPORTED_PUBLIC ReaperClaim {
121 public:
122 ReaperClaim();
123 ReaperClaim(ReaperClaim&& other) noexcept;
124 ~ReaperClaim();
125
126 ReaperClaim& operator=(ReaperClaim&& other) noexcept;
127
128 explicit operator bool() const {
129 return m_pProcess != nullptr;
130 }
131
132 void publish();
133
134 private:
135 friend class Process;
136 explicit ReaperClaim(Process* process);
137
138 ReaperClaim(const ReaperClaim&) = delete;
139 ReaperClaim& operator=(const ReaperClaim&) = delete;
140
141 Process* m_pProcess;
142 TerminationDeferral m_TerminationDeferral;
143 };
144
153 class EXPORTED_PUBLIC ThreadLease {
154 public:
155 ThreadLease();
156 ThreadLease(ThreadLease&& other) noexcept;
157 ~ThreadLease();
158
159 ThreadLease& operator=(ThreadLease&& other) noexcept;
160
161 Thread* get() const {
162 return m_pThread;
163 }
164
165 Thread* operator->() const {
166 return m_pThread;
167 }
168
169 explicit operator bool() const {
170 return m_pThread != nullptr;
171 }
172
173 void reset();
174
175 private:
176 friend class Process;
177
178 ThreadLease(Process* process, Thread* thread);
179 ThreadLease(const ThreadLease&) = delete;
180 ThreadLease& operator=(const ThreadLease&) = delete;
181
182 Process* m_pProcess;
183 Thread* m_pThread;
184 TerminationDeferral m_TerminationDeferral;
185 };
186
192 class EXPORTED_PUBLIC FileContextLease {
193 public:
196
197 File* get() const {
198 return m_pFile;
199 }
200
201 File* operator->() const {
202 return m_pFile;
203 }
204
205 explicit operator bool() const {
206 return m_pFile != nullptr;
207 }
208
209 void reset();
210
211 private:
212 friend class Process;
213
214 FileContextLease(const FileContextLease&) = delete;
215 FileContextLease& operator=(const FileContextLease&) = delete;
217 FileContextLease& operator=(FileContextLease&&) = delete;
218
219 void adopt(File* file, bool vfsReference);
220 void swap(FileContextLease& other);
221
222 File* m_pFile;
223 bool m_bVfsReference;
224 TerminationDeferral m_TerminationDeferral;
225 };
226
231 class EXPORTED_PUBLIC TerminalOwnerReservation {
232 public:
236
237 TerminalOwnerReservation& operator=(TerminalOwnerReservation&& other) noexcept;
238
239 explicit operator bool() const {
240 return m_pProcess != nullptr;
241 }
242
244 void install(Thread* owner);
245
246 private:
247 friend class Process;
248
250 TerminalOwnerReservation& operator=(const TerminalOwnerReservation&) = delete;
251
252 Process* m_pProcess;
253 TerminationDeferral m_TerminationDeferral;
254 };
255
262 enum ProcessType { Stock, Posix };
263
270 Active,
271 Suspended,
272 Terminating,
273 Terminated,
275 };
276
277#if PEDIGREE_BENCHMARK_SYSCALL_TRACE
278 void setBenchmarkSyscallTrace(bool enabled) {
279 __atomic_store_n(&m_BenchmarkSyscallTrace, enabled, __ATOMIC_RELEASE);
280 }
281
282 bool benchmarkSyscallTraceEnabled() const {
283 return __atomic_load_n(&m_BenchmarkSyscallTrace, __ATOMIC_ACQUIRE);
284 }
285#endif
286
287#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
288 static constexpr size_t SyscallTimingRawSlotCount = 512;
289 static constexpr size_t SyscallTimingOverflowSlot = SyscallTimingRawSlotCount;
290 static constexpr size_t SyscallTimingSlotCount = SyscallTimingRawSlotCount + 1;
291
292 struct SyscallTimingEntry {
293 uint64_t calls;
294 uint64_t kernelNanoseconds;
295 };
296
297 static size_t syscallTimingSlot(size_t rawNumber) {
298 return rawNumber < SyscallTimingRawSlotCount ? rawNumber : SyscallTimingOverflowSlot;
299 }
300
301 void setBenchmarkSyscallTiming(bool enabled) {
302 __atomic_store_n(&m_BenchmarkSyscallTiming, enabled, __ATOMIC_RELEASE);
303 }
304
305 bool benchmarkSyscallTimingEnabled() const {
306 return __atomic_load_n(&m_BenchmarkSyscallTiming, __ATOMIC_ACQUIRE);
307 }
308
309 void recordSyscallTimingCall(size_t slot) {
310 __atomic_fetch_add(&m_SyscallTimingCalls[slot], static_cast<uint64_t>(1), __ATOMIC_RELAXED);
311 }
312
313 void recordSyscallTimingKernel(size_t slot, Time::Timestamp elapsed) {
314 __atomic_fetch_add(&m_SyscallTimingKernelNanoseconds[slot], elapsed, __ATOMIC_RELAXED);
315 }
316
317 void getSyscallTimingEntry(size_t slot, SyscallTimingEntry& result) const {
318 result.calls = __atomic_load_n(&m_SyscallTimingCalls[slot], __ATOMIC_ACQUIRE);
319 result.kernelNanoseconds =
320 __atomic_load_n(&m_SyscallTimingKernelNanoseconds[slot], __ATOMIC_ACQUIRE);
321 }
322#endif
323
324#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
325 enum BenchmarkVmCounter : size_t {
326 VmMmapCalls,
327 VmMmapAnonymousCalls,
328 VmMmapFileCalls,
329 VmMmapPages,
330 VmMmapLength1,
331 VmMmapLength2To3,
332 VmMmapLength4To15,
333 VmMmapLength16To63,
334 VmMmapLength64To255,
335 VmMmapLength256Plus,
336 VmPublishCalls,
337 VmPublishObjectCount,
338 VmPublishOverlapProbeVisits,
339 VmPublishOverlapHits,
340 VmPublishCommitRetries,
341 VmReservationSnapshots,
342 VmReservationExtents,
343 VmReservationScratchAllocations,
344 VmMunmapCalls,
345 VmMunmapPages,
346 VmMunmapLength1,
347 VmMunmapLength2To3,
348 VmMunmapLength4To15,
349 VmMunmapLength16To63,
350 VmMunmapLength64To255,
351 VmMunmapLength256Plus,
352 VmRemoveCalls,
353 VmRemoveObjectCount,
354 VmRemoveObjectVisits,
355 VmRemoveSliceCalls,
356 VmRemoveAffectedObjects,
357 VmAllowsCalls,
358 VmAllowsObjectCount,
359 VmAllowsObjectVisits,
360 VmFaultInRangeCalls,
361 VmFaultInRangePages,
362 VmFaultInObjectVisits,
363 VmFaultInPresent,
364 VmFaultInCopyOnWrite,
365 VmFaultInTrap,
366 VmFaultCalls,
367 VmFaultObjectCount,
368 VmFaultObjectVisits,
369 VmFaultResolved,
370 VmFaultBacking,
371 VmFaultUnhandled,
372 VmGuardEntries,
373 VmGuardRecursiveEntries,
374 VmDiscardTrackedPages,
375 VmDiscardMappedPages,
376 VmTableRetirementScans,
377 VmDetachPteEntries,
378 VmDetachPdeEntries,
379 VmDetachPdptEntries,
380 VmDetachTables,
381 VmInvalidationActive,
382 VmInvalidationInactive,
383 BenchmarkVmCounterCount,
384 };
385
386 void setBenchmarkVmDiagnostics(bool enabled) {
387 __atomic_store_n(&m_BenchmarkVmDiagnostics, enabled, __ATOMIC_RELEASE);
388 }
389
390 bool benchmarkVmDiagnosticsEnabled() const {
391 return __atomic_load_n(&m_BenchmarkVmDiagnostics, __ATOMIC_ACQUIRE);
392 }
393
394 void recordBenchmarkVmCounter(BenchmarkVmCounter counter, uint64_t amount = 1) {
395 if (benchmarkVmDiagnosticsEnabled() && amount) {
396 __atomic_fetch_add(&m_BenchmarkVmCounters[counter], amount, __ATOMIC_RELAXED);
397 }
398 }
399
400 uint64_t getBenchmarkVmCounter(size_t counter) const {
401 return __atomic_load_n(&m_BenchmarkVmCounters[counter], __ATOMIC_ACQUIRE);
402 }
403#endif
404
406 Process();
407
415 Process(Process* pParent, bool bCopyOnWrite = true);
416
418 virtual ~Process();
419
422 size_t addThread(Thread* pThread);
424 void threadExiting(Thread* pThread);
426 void transferExecProcessSignals(Thread* pThread);
428 void removeThread(Thread* pThread);
429
431 size_t getNumThreads();
436 MUST_USE_RESULT bool acquireThread(ThreadLease& lease, size_t n);
437
439 MUST_USE_RESULT bool acquireProcessSignalThread(ThreadLease& lease);
440
445 MUST_USE_RESULT bool acquireThreadById(ThreadLease& lease, size_t id);
446
447 MUST_USE_RESULT bool acquireThreadByTaskId(ThreadLease& lease, size_t id);
448
453 MUST_USE_RESULT bool acquireThread(ThreadLease& lease, Thread* expected);
454
460 TerminalOwnerReservation reserveTerminalOwner();
461
463 size_t getId() {
464 return m_Id;
465 }
466
468 size_t getUserspaceId() const {
469 return m_UserspaceId;
470 }
471
474 return str;
475 }
476
479 return m_pAddressSpace;
480 }
481
482 class EXPORTED_PUBLIC VforkCompletion {
483 public:
484 void wait();
485 void complete();
486
487 private:
488 WaitQueue m_Waiters;
489 bool m_Complete = false;
490 };
491
494 return m_pVforkOwner ? m_pVforkOwner : this;
495 }
496 bool isVforkChild() const {
497 return m_pVforkOwner != nullptr;
498 }
499 void borrowVforkAddressSpace(Process& parent, const SharedPointer<VforkCompletion>& completion);
501 void releaseVforkAddressSpace();
502
504 void setExitStatus(int code) {
505 m_ExitStatus = code;
506 }
509 return m_ExitStatus;
510 }
511
512 enum class ChildTransitionKind {
513 None,
514 Stopped,
515 Continued,
516 };
517
519 ChildTransition() : kind(ChildTransitionKind::None), stopSignal(0) {}
520
521 ChildTransitionKind kind;
522 int stopSignal;
523 };
524
531 void reap();
532
534 bool prepareThreadExit();
535
541 bool beginTermination(int code = 0, Subsystem::ExitCause cause = Subsystem::ExitCause::Normal);
542
547 bool quiesceTermination();
548
550 void finishTermination(bool notifyParent = false) NORETURN;
551
553 ReaperClaim tryClaimReaper();
554
556 void kill() NORETURN;
558 void suspend(int stopSignal = 0);
560 void suspendIfContinuationEpoch(int stopSignal, size_t continuationEpoch);
562 void resume();
563
565 size_t getContinuationEpoch();
566
568 Process* getParent() {
569 return __atomic_load_n(&m_pParent, __ATOMIC_ACQUIRE);
570 }
571
572 enum class FilesystemContextMode { Inherit, Deferred };
573
574 FilesystemContextRef acquireFilesystemContext() const;
576 MUST_USE_RESULT bool installFilesystemContext(FilesystemContextOwner&& context);
577 bool filesystemContextReady() const;
578 void releaseFilesystemContext();
579
580 class EXPORTED_PUBLIC ControllingTerminal {
581 public:
582 virtual ~ControllingTerminal() = default;
583 virtual File* file() const = 0;
584 };
585
586 SharedPointer<ControllingTerminal> acquireCttyContext() const;
587 MUST_USE_RESULT File* acquireCtty(FileContextLease& lease) const;
588 void setCttyContext(const SharedPointer<ControllingTerminal>& context);
590 MUST_USE_RESULT bool setCtty(File* file);
591
592 enum class UserRegion { Normal, Dynamic };
593
595 UserReservationSnapshot() : normal(false), dynamic(false), generation(0) {}
596 MemoryAllocator normal;
597 MemoryAllocator dynamic;
598 uint64_t generation;
599 };
600
601 bool snapshotUserReservations(UserReservationSnapshot& result);
603 bool commitUserReservations(uint64_t expectedGeneration, UserReservationSnapshot& replacement);
604 bool allocateUserRange(UserRegion region, size_t length, uintptr_t& address);
605 bool allocateSpecificUserRange(UserRegion region, uintptr_t address, size_t length);
606 void freeUserRange(UserRegion region, uintptr_t address, size_t length);
607 void resetUserReservations();
608
609 virtual bool snapshotFilesystemCredentials(const Thread* task, FilesystemCredentials& out) const;
610 static bool currentFilesystemCredentials(FilesystemCredentials& out);
611 void inheritFilesystemIds(Thread& child, const Thread* creator) const;
612 virtual bool installUserIdentity(User*, Group*, const uint32_t* groups, size_t count);
613
614 class EXPORTED_PUBLIC FilesystemAccessScope {
615 public:
616 explicit FilesystemAccessScope(const FilesystemCredentials& credentials);
618
619 private:
621 FilesystemAccessScope& operator=(const FilesystemAccessScope&) = delete;
622 Uninterruptible m_Events;
623 TerminationDeferral m_Termination;
624 FilesystemCredentials m_Credentials;
625 Thread* m_Thread;
626 const FilesystemCredentials* m_Previous;
627 };
628
630 User* getUser() const;
632 void setUser(User* pUser);
633
635 User* getEffectiveUser() const;
637 void setEffectiveUser(User* pUser);
638
640 Group* getGroup() const;
642 void setGroup(Group* pGroup);
643
645 Group* getEffectiveGroup() const;
646 void setEffectiveGroup(Group* pGroup);
647
650 virtual int64_t getUserId() const;
651 virtual int64_t getGroupId() const;
652 virtual int64_t getEffectiveUserId() const;
653 virtual int64_t getEffectiveGroupId() const;
654 virtual void getSupplementalGroupIds(Vector<int64_t>& vec) const;
655 virtual void setUserId(int64_t id);
656 virtual void setGroupId(int64_t id);
657 virtual void setEffectiveUserId(int64_t id);
658 virtual void setEffectiveGroupId(int64_t id);
659
660 void setLinker(DynamicLinker* pDl) {
661 m_pDynamicLinker = pDl;
662 }
663 DynamicLinker* getLinker() {
664 return m_pDynamicLinker;
665 }
666
667 void setSubsystem(Subsystem* pSubsystem) {
668 m_pSubsystem = pSubsystem;
669 m_pSubsystem->setProcess(this);
670 }
671 Subsystem* getSubsystem() {
672 return m_pSubsystem;
673 }
674
675 ProcessType getType() const {
676 return m_Type;
677 }
678
683 return m_ChildStateWaiters.acquire();
684 }
685
690 bool waitUntilTerminationReapable();
691
696 bool waitUntilTerminationReapableForTerminalCoordinator();
697
703 bool selectPendingChildTransition(bool includeStopped, bool includeContinued, bool consume,
704 ChildTransition& transition);
705
707 bool takePendingChildTransition(bool includeStopped, bool includeContinued,
708 ChildTransition& transition);
709
710 ProcessState getState() const {
711 return __atomic_load_n(&m_State, __ATOMIC_ACQUIRE);
712 }
713
714 bool isSuspended() {
715 return getState() == Suspended;
716 }
717
718 void markTerminating();
719
720#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
721 using TerminationElectionHook = void (*)(Process*, Thread*);
722 static void setTerminationElectionHook(TerminationElectionHook hook);
723
724 enum ExternalLeaseReleasePhase {
725 ExternalLeaseFinalReleaseUnlocked,
726 ExternalLeaseBeforeWaiterWake,
727 };
728 using ExternalLeaseReleaseHook = void (*)(Process*, ExternalLeaseReleasePhase);
729 static void setExternalLeaseReleaseHookForHostedTest(Process* target,
730 ExternalLeaseReleaseHook hook);
731
733 bool isTerminationReapableForHostedTest();
734
735 enum class OrphanPublicationPhase {
736 Preparing,
737 Published,
738 };
739 using OrphanPublicationHook = void (*)(Process*, OrphanPublicationPhase, bool interruptsEnabled,
740 bool processLockHeld);
741 static void setOrphanPublicationHook(OrphanPublicationHook hook);
742
744 void publishTimeAccountingForHostedTest(Time::Timestamp user, Time::Timestamp system);
745
747 void closeTimeAccountingForHostedTest();
748
749 bool timeAccountingPendingForHostedTest() const {
750 return m_DeferredTimeAccounting.pending();
751 }
752 size_t timeAccountingInterestForHostedTest() const {
753 return __atomic_load_n(&m_TimeAccountingReportInterest, __ATOMIC_ACQUIRE);
754 }
755#endif
756
757 void trackHeap(ssize_t nBytes) {
758 __atomic_fetch_add(&m_Metadata.heapUsage, nBytes, __ATOMIC_RELAXED);
759 }
760
761 void trackPages(ssize_t nVirtual, ssize_t nPhysical, ssize_t nShared) {
762 __atomic_fetch_add(&m_Metadata.virtualPages, nVirtual, __ATOMIC_RELAXED);
763 __atomic_fetch_add(&m_Metadata.physicalPages, nPhysical, __ATOMIC_RELAXED);
764 __atomic_fetch_add(&m_Metadata.sharedPages, nShared, __ATOMIC_RELAXED);
765 }
766
767 void resetCounts() {
768 __atomic_store_n(&m_Metadata.virtualPages, static_cast<ssize_t>(0), __ATOMIC_RELEASE);
769 __atomic_store_n(&m_Metadata.physicalPages, static_cast<ssize_t>(0), __ATOMIC_RELEASE);
770 __atomic_store_n(&m_Metadata.sharedPages, static_cast<ssize_t>(0), __ATOMIC_RELEASE);
771 __atomic_store_n(&m_Metadata.startTime, Time::getTimeNanoseconds(), __ATOMIC_RELEASE);
772 }
773
775 Time::Timestamp getUserTime() const {
776 return m_PerCpuTimeAccounting.total(CpuTimeMode::User) +
777 __atomic_load_n(&m_Metadata.userTime, __ATOMIC_ACQUIRE);
778 }
779 Time::Timestamp getKernelTime() const {
780 return m_PerCpuTimeAccounting.total(CpuTimeMode::Kernel) +
781 __atomic_load_n(&m_Metadata.kernelTime, __ATOMIC_ACQUIRE);
782 }
783 Time::Timestamp getReapedChildrenUserTime() const {
784 return __atomic_load_n(&m_Metadata.reapedChildrenUserTime, __ATOMIC_ACQUIRE);
785 }
786 Time::Timestamp getReapedChildrenKernelTime() const {
787 return __atomic_load_n(&m_Metadata.reapedChildrenKernelTime, __ATOMIC_ACQUIRE);
788 }
789
790#if PEDIGREE_SYSCALL_COUNTER
791 static constexpr size_t SyscallLatencyBucketCount = 16;
792
793 struct SyscallLatencySnapshot {
794 uint64_t buckets[SyscallLatencyBucketCount];
795 };
796
798 void recordSyscall() {
799 __atomic_fetch_add(&m_Metadata.syscallCount, static_cast<uint64_t>(1), __ATOMIC_RELAXED);
800 }
801
803 void recordSyscallDuration(Time::Timestamp duration) {
804 size_t bucket = 0;
805 Time::Timestamp limit = Time::Multiplier::Microsecond;
806 while (bucket + 1 < SyscallLatencyBucketCount && duration >= limit) {
807 ++bucket;
808 limit <<= 1;
809 }
810 __atomic_fetch_add(&m_Metadata.syscallLatencyBuckets[bucket], static_cast<uint64_t>(1),
811 __ATOMIC_RELAXED);
812 }
813
814 uint64_t getSyscallCount() const {
815 return __atomic_load_n(&m_Metadata.syscallCount, __ATOMIC_ACQUIRE);
816 }
817
818 uint64_t getReapedChildrenSyscallCount() const {
819 return __atomic_load_n(&m_Metadata.reapedChildrenSyscallCount, __ATOMIC_ACQUIRE);
820 }
821
822 void getSyscallLatencySnapshot(SyscallLatencySnapshot& snapshot) const {
823 for (size_t i = 0; i < SyscallLatencyBucketCount; ++i) {
824 snapshot.buckets[i] =
825 __atomic_load_n(&m_Metadata.syscallLatencyBuckets[i], __ATOMIC_ACQUIRE) +
826 __atomic_load_n(&m_Metadata.reapedChildrenSyscallLatencyBuckets[i], __ATOMIC_ACQUIRE);
827 }
828 }
829
830 void getReapedChildrenSyscallLatencySnapshot(SyscallLatencySnapshot& snapshot) const {
831 for (size_t i = 0; i < SyscallLatencyBucketCount; ++i) {
832 snapshot.buckets[i] =
833 __atomic_load_n(&m_Metadata.reapedChildrenSyscallLatencyBuckets[i], __ATOMIC_ACQUIRE);
834 }
835 }
836#endif
837
843 void accountReapedChild(const Process* child, Time::Timestamp& user, Time::Timestamp& kernel);
844
845 Time::Timestamp getStartTime() const {
846 return __atomic_load_n(&m_Metadata.startTime, __ATOMIC_ACQUIRE);
847 }
848
850 ssize_t getHeapUsage() const {
851 return __atomic_load_n(&m_Metadata.heapUsage, __ATOMIC_ACQUIRE);
852 }
853 ssize_t getVirtualPageCount() const {
854 return __atomic_load_n(&m_Metadata.virtualPages, __ATOMIC_ACQUIRE);
855 }
856 ssize_t getPhysicalPageCount() const {
857 return __atomic_load_n(&m_Metadata.physicalPages, __ATOMIC_ACQUIRE);
858 }
859 ssize_t getSharedPageCount() const {
860 return __atomic_load_n(&m_Metadata.sharedPages, __ATOMIC_ACQUIRE);
861 }
862
868 return m_bSharedAddressSpace;
869 }
870
875 static Process* getInit();
876
878 static void setInit(Process* pProcess);
879
880 protected:
881 mutable Spinlock m_CredentialLock;
882 static bool loadFilesystemIds(const Thread&, uint32_t& uid, uint32_t& gid);
883 static void publishFilesystemIds(Thread&, uint32_t uid, uint32_t gid);
884 void publishAccountIdentity(User*, Group*);
885
891
893 Process(DeferredPublication, Process* pParent, bool bCopyOnWrite = true,
894 FilesystemContextMode filesystemContext = FilesystemContextMode::Inherit,
895 bool emptyAddressSpace = false, ProcessType type = Stock);
896
898 void publish();
899
900#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
905 void makeOrphanBeforePublicationForHostedTest();
906#endif
907
914 void prepareForDestruction();
915
917 void enableTimeAccountingReports(size_t initialInterest = ~size_t(0));
918
920 void setTimeAccountingReportInterest(size_t interest, bool enabled);
921
922 private:
923 void finishTermination(bool abandonStack, bool notifyParent) NORETURN;
924
925 Process(const Process&);
926 Process& operator=(const Process&);
927
932 virtual void reportTimesUpdated(Time::Timestamp userTotal, Time::Timestamp total) {}
933
935 void drainDeferredTimeAccounting();
936
938 void closeDeferredTimeAccounting();
939
941 ALWAYS_INLINE void publishTimeAccounting(CpuTimeMode mode, Time::Timestamp elapsed,
942 size_t processor) {
943 if (!m_PerCpuTimeAccounting.add(mode, elapsed, processor)) {
944 Time::Timestamp* total =
945 mode == CpuTimeMode::User ? &m_Metadata.userTime : &m_Metadata.kernelTime;
946 __atomic_fetch_add(total, elapsed, __ATOMIC_RELAXED);
947 }
948 reportTimeAccounting(elapsed);
949 }
950
951 ALWAYS_INLINE void reportTimeAccounting(Time::Timestamp elapsed) {
952 // Most processes have no armed CPU-time timer. Keep that path free of
953 // worker publication and its lifecycle-admission load.
954 if (__atomic_load_n(&m_TimeAccountingReportInterest, __ATOMIC_ACQUIRE) &&
955 __atomic_load_n(&m_bTimeAccountingReportsEnabled, __ATOMIC_ACQUIRE)) {
956 queueTimeAccountingReport(elapsed);
957 }
958 }
959
960 void queueTimeAccountingReport(Time::Timestamp elapsed);
961
963 virtual void processTerminated() {}
964
976 size_t m_Id;
993 VirtualAddressSpace* m_pVforkPrivateAddressSpace = nullptr;
994 Process* m_pVforkOwner = nullptr;
995 SharedPointer<VforkCompletion> m_VforkCompletion;
1000 FilesystemContextOwner m_FilesystemContext;
1001 bool m_bFilesystemContextReady;
1014 Spinlock m_UserReservationLock;
1015 uint64_t m_UserReservationGeneration;
1016
1017#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
1018 bool m_BenchmarkSyscallTiming = false;
1019 uint64_t m_SyscallTimingCalls[SyscallTimingSlotCount] = {};
1020 uint64_t m_SyscallTimingKernelNanoseconds[SyscallTimingSlotCount] = {};
1021#endif
1022
1023#if PEDIGREE_BENCHMARK_SYSCALL_TRACE
1024 bool m_BenchmarkSyscallTrace = false;
1025#endif
1026
1027#if PEDIGREE_BENCHMARK_VM_DIAGNOSTICS
1028 bool m_BenchmarkVmDiagnostics = false;
1029 uint64_t m_BenchmarkVmCounters[BenchmarkVmCounterCount] = {};
1030#endif
1031
1034 User* m_pUser;
1041
1044
1047
1050
1053
1056
1059
1062
1065
1068
1074
1077
1080
1083
1086
1089
1092
1093 // Construction selects the actual class, independently of the parent's type.
1094 const ProcessType m_Type;
1095
1101 bool transitionState(ProcessState expected, ProcessState desired);
1102
1104 void suspendInternal(int stopSignal, bool checkContinuationEpoch, size_t continuationEpoch);
1105
1107 void transitionToTerminating();
1108
1111
1114
1117
1120
1122 Thread* m_pExecOwner = nullptr;
1123 bool m_bExecCommitted = false;
1124 bool m_bExecExitForwarded = false;
1125 size_t m_nThreadCreations = 0;
1126 WaitQueue m_ExecWaiters;
1127
1130
1133
1136
1139
1142
1145
1148
1149 enum ReaperState {
1150 ReaperUnclaimed,
1151 ReaperClaimed,
1152 ReaperPublished,
1153 };
1154
1157
1160
1166 bool terminatingThreadReapable(Thread* pThread, bool& wakeOwner);
1167
1169 void publishTerminationStatus(bool notifyParent);
1170
1172 void publishTerminationReapable();
1173
1175 void publishReaperClaim();
1176
1178 bool beginThreadJoin();
1179
1181 void endThreadJoin();
1182
1184 bool beginExternalLease();
1185
1187 void endExternalLease();
1188
1190 void closeExternalLeaseAdmission();
1191
1193 void drainExternalLeases();
1194
1196 void releaseThreadLease(Thread* thread);
1197
1199 void installTerminalOwner(Thread* owner);
1200
1203#if PEDIGREE_SYSCALL_COUNTER
1205 : heapUsage(0),
1206 virtualPages(0),
1207 physicalPages(0),
1208 sharedPages(0),
1209 userTime(0),
1210 kernelTime(0),
1211 reapedChildrenUserTime(0),
1212 reapedChildrenKernelTime(0),
1213 syscallCount(0),
1214 reapedChildrenSyscallCount(0),
1215 syscallLatencyBuckets{},
1216 reapedChildrenSyscallLatencyBuckets{},
1217 startTime(0) {}
1218#else
1220 : heapUsage(0),
1221 virtualPages(0),
1222 physicalPages(0),
1223 sharedPages(0),
1224 userTime(0),
1225 kernelTime(0),
1226 reapedChildrenUserTime(0),
1227 reapedChildrenKernelTime(0),
1228 startTime(0) {}
1229#endif
1230
1232 ssize_t heapUsage;
1240
1242 Time::Timestamp userTime;
1243 Time::Timestamp kernelTime;
1245 Time::Timestamp reapedChildrenUserTime;
1248
1249#if PEDIGREE_SYSCALL_COUNTER
1251 uint64_t syscallCount;
1253 uint64_t reapedChildrenSyscallCount;
1255 uint64_t syscallLatencyBuckets[SyscallLatencyBucketCount];
1257 uint64_t reapedChildrenSyscallLatencyBuckets[SyscallLatencyBucketCount];
1258#endif
1259
1261 Time::Timestamp startTime;
1262 } m_Metadata;
1263
1270
1273
1276
1279
1282
1283 size_t m_TimeAccountingReportInterest;
1284
1287
1290
1291#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
1292 static TerminationElectionHook m_TerminationElectionHook;
1293 static ExternalLeaseReleaseHook m_ExternalLeaseReleaseHook;
1294 static Process* m_ExternalLeaseReleaseTarget;
1295 static OrphanPublicationHook m_OrphanPublicationHook;
1296#endif
1297};
1298
1299#endif
Definition File.h:74
Definition Group.h:32
Definition Mutex.h:56
Group * m_pGroup
Definition Process.h:1036
virtual void reportTimesUpdated(Time::Timestamp userTotal, Time::Timestamp total)
Definition Process.h:932
size_t getUserspaceId() const
Definition Process.h:468
void setExitStatus(int code)
Definition Process.h:504
ProcessState
Definition Process.h:269
@ Reaped
Terminal wait status is visible; the owner may still be on-stack.
Definition Process.h:274
ssize_t getHeapUsage() const
Definition Process.h:850
FilesystemCredentials m_NativeFilesystemCredentials
Definition Process.h:1033
bool m_bTerminalOwnerReserved
Definition Process.h:1135
Process * m_pParent
Definition Process.h:988
size_t getId()
Definition Process.h:463
Subsystem * m_pSubsystem
Definition Process.h:1046
virtual void processTerminated()
Definition Process.h:963
LargeStaticString str
Definition Process.h:984
Group * m_pEffectiveGroup
Definition Process.h:1040
SharedPointer< UserspacePidNamespace > m_UserspaceNamespace
Definition Process.h:978
int getExitStatus()
Definition Process.h:508
PerCpuTimeAccounting m_PerCpuTimeAccounting
Definition Process.h:1269
bool m_bPublished
Definition Process.h:1113
bool m_bUnregistered
Definition Process.h:1116
VirtualAddressSpace * getAddressSpace()
Definition Process.h:478
size_t m_nTerminationParticipants
Definition Process.h:1129
size_t m_nThreadJoinOperations
Definition Process.h:1064
bool m_bExternalLeaseAdmissionClosed
Definition Process.h:1082
bool hasSharedAddressSpace() const
Definition Process.h:867
WaitQueue::Guard acquireChildStateWait()
Definition Process.h:682
ProcessType
Definition Process.h:262
bool m_bTerminationReapable
Definition Process.h:1147
bool m_bSharedAddressSpace
Definition Process.h:1286
size_t m_ReaperState
Definition Process.h:1156
Atomic< size_t > m_NextTid
Definition Process.h:972
Thread * m_pReservedTerminalOwner
Definition Process.h:1138
static Process * m_pInitProcess
Definition Process.h:1289
int m_ExitStatus
Definition Process.h:997
WaitQueue m_ExternalLeaseWaiters
Definition Process.h:1076
OperationBarrier m_DeferredThreadReaps
Definition Process.h:1278
DynamicLinker * m_pDynamicLinker
Definition Process.h:1043
Spinlock m_ExternalLeaseLock
Definition Process.h:1073
VirtualAddressSpace * m_pAddressSpace
Definition Process.h:992
bool m_bTerminationRendezvousStarted
Definition Process.h:1132
OperationBarrier m_TimeAccountingReports
Definition Process.h:1275
LargeStaticString & description()
Definition Process.h:473
ALWAYS_INLINE void publishTimeAccounting(CpuTimeMode mode, Time::Timestamp elapsed, size_t processor)
Definition Process.h:941
User * m_pEffectiveUser
Definition Process.h:1038
Spinlock m_Lock
Definition Process.h:1159
bool m_bDestroying
Definition Process.h:1110
WaitQueue m_ThreadJoinWaiters
Definition Process.h:1061
Time::Timestamp getUserTime() const
Definition Process.h:775
Process * addressSpaceOwner()
Definition Process.h:493
bool m_bTerminationCleanupStarted
Definition Process.h:1141
bool m_bTimeAccountingReportsEnabled
Definition Process.h:1281
DeferredTimeAccounting m_DeferredTimeAccounting
Definition Process.h:1272
size_t m_Id
Definition Process.h:976
Mutex m_FilesystemContextLock
Definition Process.h:999
size_t m_nExternalLeases
Definition Process.h:1079
bool m_bTerminationSealed
Definition Process.h:1144
WaitQueue m_SuspensionWaiters
Definition Process.h:1055
bool m_bExternalLeaseReleaseInProgress
Definition Process.h:1085
SharedPointer< ControllingTerminal > m_Ctty
Definition Process.h:1005
ChildTransition m_PendingChildTransition
Definition Process.h:1088
MemoryAllocator m_DynamicSpaceAllocator
Definition Process.h:1013
MemoryAllocator m_SpaceAllocator
Definition Process.h:1009
Thread * m_pTerminatingThread
Definition Process.h:1119
WaitQueue m_ChildStateWaiters
Definition Process.h:1049
bool m_bThreadJoinAdmissionClosed
Definition Process.h:1067
ProcessState m_State
Definition Process.h:1091
WaitQueue m_TerminationWaiters
Definition Process.h:1052
Vector< Thread * > m_Threads
Definition Process.h:968
size_t m_UserspaceId
Definition Process.h:980
size_t m_ContinuationEpoch
Definition Process.h:1058
This class manages how processes and threads are scheduled across processors.
Definition Scheduler.h:50
virtual void setProcess(Process *p)
Definition Subsystem.h:145
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:1237
ssize_t sharedPages
Shared pages consumed.
Definition Process.h:1239
ssize_t heapUsage
Bytes used in the kernel heap by this process.
Definition Process.h:1232
Time::Timestamp reapedChildrenUserTime
Time spent in userspace by children this process has reaped.
Definition Process.h:1245
Time::Timestamp userTime
CPU time published without an allocated local shard.
Definition Process.h:1242
Time::Timestamp startTime
Time at which process started.
Definition Process.h:1261
Time::Timestamp reapedChildrenKernelTime
Time spent in the kernel by children this process has reaped.
Definition Process.h:1247