PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/base/Kernel/Singularity/Process.cs

https://bitbucket.org/MpDzik/singularity-bus-drivers
C# | 2078 lines | 1561 code | 246 blank | 271 comment | 278 complexity | 9c3a05978d40e64e03d9216b8c9965f5 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft Research Singularity
  4. //
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. //
  7. // File: Process.cs
  8. //
  9. // Note:
  10. //
  11. // #define TEST_CREATE_PROCESS_TIME
  12. // #define VERBOSE
  13. // #define APPLY_TPM
  14. using System;
  15. using System.Collections;
  16. using System.Diagnostics;
  17. using System.Runtime.CompilerServices;
  18. using System.Runtime.InteropServices;
  19. using System.Threading;
  20. using Microsoft.Singularity;
  21. using Microsoft.Singularity.Io;
  22. using Microsoft.Singularity.Xml;
  23. using Microsoft.Singularity.Loader;
  24. using Microsoft.Singularity.Memory;
  25. using Microsoft.Singularity.Directory;
  26. using Microsoft.Singularity.Scheduling;
  27. using Microsoft.Singularity.V1.Threads;
  28. using Microsoft.Singularity.V1.Services;
  29. using Microsoft.Singularity.Security;
  30. using Microsoft.Singularity.Eventing;
  31. namespace Microsoft.Singularity
  32. {
  33. [CLSCompliant(false)]
  34. public enum ProcessEvent : ushort
  35. {
  36. CreateKernelProcess = 1,
  37. CreateUserProcess = 2,
  38. ImageLoad = 3,
  39. }
  40. //
  41. // Per-SIP privileges. They are available only to the kernel side of the process
  42. // They cannot also be altered by the SIP, assumming strong guarantees about mnemory
  43. // safety.
  44. //
  45. [CLSCompliant(false)]
  46. public class ProcessPrivileges
  47. {
  48. //
  49. // Default privileges for processes which do not override them from a
  50. // trusted component base.
  51. //
  52. public static ProcessPrivileges DefaultPrivileges = new ProcessPrivileges(Operations.None);
  53. [Flags]
  54. public enum Operations
  55. {
  56. None = 0,
  57. // This privilege is checked for operations such as enabling / disabling
  58. // interrupts and querying the interrupts flag. SIP should not have this
  59. // privilege set by default, with the few exceptions of drivers
  60. DisableInterrupts = 1,
  61. };
  62. public ProcessPrivileges(Operations allowedOpperations)
  63. {
  64. AllowedOperations = allowedOpperations;
  65. }
  66. [NoHeapAllocation]
  67. public static ProcessPrivileges GetCurrentPrivileges()
  68. {
  69. Process process = Thread.CurrentProcess;
  70. // The privileges should only be checked within a valid context
  71. VTable.Assert(process != null);
  72. return process.GetPrivileges();
  73. }
  74. public readonly Operations AllowedOperations;
  75. }
  76. [NoCCtor]
  77. [CLSCompliant(false)]
  78. public class Process
  79. {
  80. // Per-Class Members:
  81. internal static HandleTable kernelHandles;
  82. public static bool systemSilentLoad;
  83. public static Process kernelProcess;
  84. public static Process idleProcess;
  85. public static Process[] processTable;
  86. private static SpinLock processTableLock;
  87. private static int processIndexGenerator;
  88. internal const int maxProcesses = 1024; // Must be power of 2 >= 64
  89. private static bool useSeparateAddressSpaces;
  90. private static ProcessGroup [] processGroups;
  91. // Xml processing constants
  92. internal const string PolicyXmlTag = "policy";
  93. internal const string ProcessSetXmlTag = "processSet";
  94. internal const string SeparateAddressSpaceXmlAttribute = "separateAddressSpace";
  95. internal const string NameXmlAttribute = "name";
  96. internal const string SetXmlAttribute = "set";
  97. internal const string KernelDomainXmlAttribute = "kernelDomain";
  98. public enum ParameterCode {
  99. Success,
  100. OutOfRange,
  101. NotSet,
  102. Retrieved,
  103. AlreadySet,
  104. Undefined,
  105. }
  106. // Arrays used set/get process arguments
  107. private class BoolArg {
  108. public bool Value;
  109. public bool Set;
  110. public bool Retrieved;
  111. public BoolArg (bool value)
  112. {
  113. this.Value = value;
  114. this.Set = false;
  115. this.Retrieved = false;
  116. }
  117. }
  118. private class LongArg {
  119. public long Value;
  120. public bool Set;
  121. public bool Retrieved;
  122. public LongArg (long value)
  123. {
  124. this.Value = value;
  125. this.Set = false;
  126. this.Retrieved = false;
  127. }
  128. }
  129. private class StringArg {
  130. public string Value;
  131. public bool Set;
  132. public bool Retrieved;
  133. public StringArg (string value)
  134. {
  135. this.Value = value;
  136. this.Set = false;
  137. this.Retrieved = false;
  138. }
  139. }
  140. private class StringArrayArg
  141. {
  142. public string[] Value;
  143. public bool Set;
  144. public bool Retrieved;
  145. public StringArrayArg (string[] value)
  146. {
  147. this.Value = value;
  148. this.Set = false;
  149. this.Retrieved = false;
  150. }
  151. }
  152. internal class ProcessGroup
  153. {
  154. public string GroupName;
  155. public string [] ProcessSet;
  156. public bool KernelDomain;
  157. public ProcessGroup(string name, string[] procs, bool kernelDomain)
  158. {
  159. this.GroupName = name;
  160. this.ProcessSet = procs;
  161. this.KernelDomain = kernelDomain;
  162. }
  163. }
  164. internal static string [] Tokenize(string str) {
  165. int start = 0;
  166. int end = str.Length;
  167. int count = 0;
  168. int at = 0;
  169. ArrayList tokens = new ArrayList();
  170. string[] retVal = null;
  171. if (str == null) return null;
  172. while ((start <= end) && (at > -1)) {
  173. count = end - start;
  174. at = str.IndexOf(' ', start, count);
  175. if (at == -1) {
  176. tokens.Add(str.Substring(start));
  177. break;
  178. }
  179. string s = str.Substring(start, at-start);
  180. tokens.Add(s);
  181. start = at+1;
  182. }
  183. retVal = new string[tokens.Count];
  184. for (int i = 0; i < tokens.Count; i++) {
  185. retVal[i] = (string) tokens[i];
  186. }
  187. return retVal;
  188. }
  189. internal static void ProcessConfig (XmlNode config)
  190. {
  191. if (config == null) {
  192. return;
  193. }
  194. // process address space policy
  195. XmlNode policy = config.GetChild(PolicyXmlTag);
  196. if (policy != null) {
  197. useSeparateAddressSpaces = policy.GetAttribute(SeparateAddressSpaceXmlAttribute, false);
  198. }
  199. int groupNodes = config.CountNamedChildren(ProcessSetXmlTag);
  200. if (groupNodes != 0) {
  201. // allocate memory for groups
  202. processGroups = new ProcessGroup[groupNodes];
  203. int idx = 0;
  204. foreach (XmlNode group in config.Children) {
  205. if (group.Name != ProcessSetXmlTag) {
  206. continue;
  207. }
  208. string groupName = group.GetAttribute(NameXmlAttribute, "");
  209. string appSet = group.GetAttribute(SetXmlAttribute, "");
  210. // break up appset into array of names
  211. string[] procs = Tokenize(appSet);
  212. bool kernelDomain = group.GetAttribute(KernelDomainXmlAttribute,false);
  213. processGroups[idx] = new ProcessGroup(groupName, procs, kernelDomain);
  214. idx++;
  215. }
  216. }
  217. }
  218. internal static
  219. void VisitSpecialData(System.GCs.DirectReferenceVisitor visitor)
  220. {
  221. visitor.VisitReferenceFields(Process.processTable);
  222. for (int i = 0; i < processTable.Length; i++) {
  223. Process process = processTable[i];
  224. // Conditions to check:
  225. // 1. process is not null.
  226. // 2. process.handles is not null (during process initialization,
  227. // the process instance is added to processTable before
  228. // handles is initialized).
  229. // 3. process.processIndex is not -1 (during process shutdown,
  230. // processIndex is set to -1 as a signal that GC shouldn't
  231. // touch the pages, so the pages can be freed safely).
  232. if (process != null && process.handles != null && process.processIndex != -1) {
  233. process.handles.VisitSpecialData(visitor);
  234. }
  235. }
  236. }
  237. internal static int AllocateProcessTableSlot(Process process)
  238. {
  239. Thread currentThread = Thread.CurrentThread;
  240. Kernel.Waypoint(621);
  241. bool saved = Processor.DisableInterrupts();
  242. processTableLock.Acquire(currentThread);
  243. int foundIndex = -1;
  244. try {
  245. for (int i = 0; i < processTable.Length; i++) {
  246. int index = (processIndexGenerator + i) % processTable.Length;
  247. if (processTable[index] == null) {
  248. Kernel.Waypoint(622);
  249. foundIndex = index;
  250. processTable[foundIndex] = process;
  251. processIndexGenerator = (index + 1) % processTable.Length;
  252. break;
  253. }
  254. }
  255. }
  256. finally {
  257. processTableLock.Release(currentThread);
  258. Processor.RestoreInterrupts(saved);
  259. }
  260. Kernel.Waypoint(623);
  261. DebugStub.Assert(foundIndex >= 0, "Out of thread slots!");
  262. return foundIndex;
  263. }
  264. internal static void Initialize(XmlNode config)
  265. {
  266. // Create pre-existent processes.
  267. kernelProcess = new Process(1);
  268. idleProcess = new Process(2);
  269. // Initialize process management table.
  270. processTableLock = new SpinLock(SpinLock.Types.ProcessTable);
  271. processTable = new Process[maxProcesses];
  272. processTable[0] = kernelProcess; // ensure slot zero is never used
  273. processTable[1] = kernelProcess; // 1 is the kernel process.
  274. processTable[2] = idleProcess; // 2 is the idle process.
  275. processIndexGenerator = 3;
  276. // Create table told hold kernel handles.
  277. kernelHandles = new HandleTable(null);
  278. Thread.initialThread.process = kernelProcess;
  279. //policy config data
  280. ProcessConfig(config);
  281. }
  282. // The next 2 functions are used by the loader to determine
  283. // what address space SIPs should be created in
  284. public static bool RunInSeparateSpace()
  285. {
  286. return useSeparateAddressSpaces;
  287. }
  288. public static string GetGroupFromName(string name, out bool isKernelDomain)
  289. {
  290. isKernelDomain = false;
  291. if (processGroups == null) return null;
  292. for (int i = 0; i < processGroups.Length; i++) {
  293. for (int j = 0; j < processGroups[i].ProcessSet.Length; j++) {
  294. if (processGroups[i].ProcessSet[j] == name) {
  295. isKernelDomain = processGroups[i].KernelDomain;
  296. return processGroups[i].GroupName;
  297. }
  298. }
  299. }
  300. return null;
  301. }
  302. [NoHeapAllocation]
  303. public static Process GetProcessByID(int procID)
  304. {
  305. return processTable[procID];
  306. }
  307. // Per-Instance Members:
  308. private ProcessState state; // acquire processMutex before modifying
  309. private bool wasStarted; // were we ever in the Running state?
  310. private Mutex suspendMutex; // lock ordering: if you acquire both suspendMutex and processMutex, acquire suspendMutex first
  311. private Mutex processMutex; // lock ordering: acquire child lock before acquiring parent lock
  312. private int processIndex;
  313. private uint processTag;
  314. private Process parent;
  315. private IoConfig ioconfig;
  316. private Process[] children;
  317. private Thread[] threads;
  318. private int startedChildCount;
  319. private int startedThreadCount;
  320. private HandleTable handles;
  321. private ManualResetEvent joinEvent;
  322. private int exitCode;
  323. private bool silentLoad;
  324. private UIntPtr pagesNow;
  325. private UIntPtr pagesMax;
  326. #if false
  327. private ThreadScheduleData defaultScheduleData;
  328. #endif
  329. private PEImage image;
  330. private IoMemory loadedImage;
  331. private ProcessStart entry;
  332. private String imageName;
  333. private String[] args;
  334. private long deadThreadCount;
  335. private TimeSpan deadThreadExecutionTime;
  336. private int gcCount;
  337. private TimeSpan gcTotalTime;
  338. private long gcTotalBytes;
  339. private unsafe SharedHeap.Allocation * [] endpointSet;
  340. private BoolArg[] boolArgSet;
  341. private StringArg[] stringArgSet;
  342. private LongArg[] longArgSet;
  343. private StringArrayArg[] stringArrayArgSet;
  344. private ProtectionDomain protectionDomain;
  345. private ProcessPrivileges privileges = null;
  346. // The principal of the process
  347. private Principal principal;
  348. /// <summary>
  349. /// Get the process's current privileges
  350. /// </summary>
  351. [NoHeapAllocation]
  352. public ProcessPrivileges GetPrivileges()
  353. {
  354. if (privileges != null) {
  355. return privileges;
  356. } else {
  357. return ProcessPrivileges.DefaultPrivileges;
  358. }
  359. }
  360. [NoHeapAllocation]
  361. public void SetPrivileges(ProcessPrivileges newPrivileges)
  362. {
  363. privileges = newPrivileges;
  364. }
  365. /// <summary>
  366. /// Get the parent process
  367. /// </summary>
  368. public Process Parent
  369. {
  370. get { return parent; }
  371. }
  372. #if false
  373. internal ThreadScheduleData DefaultScheduleData
  374. {
  375. [Inline]
  376. [NoHeapAllocation]
  377. get
  378. {
  379. return defaultScheduleData;
  380. }
  381. }
  382. #endif
  383. private Process(int index)
  384. {
  385. this.state = ProcessState.Unstarted;
  386. this.suspendMutex = new Mutex();
  387. this.processMutex = new Mutex();
  388. this.processIndex = index;
  389. this.processTag = ((uint)processIndex) << 16;
  390. this.children = new Process[16];
  391. this.threads = new Thread[16];
  392. this.handles = new HandleTable(this);
  393. this.parent = null;
  394. this.joinEvent = new ManualResetEvent(false);
  395. this.imageName = index == 1 ? "kernel" : "idle";
  396. this.deadThreadCount = 0;
  397. this.deadThreadExecutionTime = new TimeSpan(0);
  398. this.gcCount = 0;
  399. this.gcTotalTime = TimeSpan.Zero;
  400. this.gcTotalBytes = 0;
  401. //DebugStub.WriteLine("new process(index): clearing StringArray");
  402. this.stringArrayArgSet = null;
  403. this.protectionDomain = ProtectionDomain.DefaultDomain;
  404. protectionDomain.AddRef();
  405. #if VERBOSE
  406. DebugStub.WriteLine("Loaded process \"{0}\" into {1}protection domain \"{2}\"",
  407. __arglist(this.imageName,
  408. this.protectionDomain.KernelMode ? "kernel " : "",
  409. this.protectionDomain.Name));
  410. #endif
  411. // This constructor is currently used only to create the
  412. // process for the kernel. If this changes, the code below should
  413. // change as well. In general, use the other constructor, as it
  414. // provides sufficient information to create the process principal.
  415. this.principal = PrincipalImpl.Self();
  416. Monitoring.Log(Monitoring.Provider.Process,
  417. (ushort)ProcessEvent.CreateKernelProcess,
  418. GetProcessName());
  419. }
  420. private Process(Process parent)
  421. {
  422. Kernel.Waypoint(620);
  423. this.processIndex = AllocateProcessTableSlot(this);
  424. #if false
  425. this.defaultScheduleData = parent.defaultScheduleData;
  426. #endif
  427. Kernel.Waypoint(625);
  428. this.state = ProcessState.Unstarted;
  429. this.suspendMutex = new Mutex();
  430. this.processMutex = new Mutex();
  431. this.processTag = ((uint)processIndex) << 16;
  432. this.children = new Process[16];
  433. this.threads = new Thread[16];
  434. this.handles = new HandleTable(this);
  435. this.parent = parent;
  436. this.imageName = parent.imageName;
  437. this.ioconfig = parent.ioconfig; // replicate IoConfig to children.
  438. Kernel.Waypoint(626);
  439. this.joinEvent = new ManualResetEvent(false);
  440. //DebugStub.WriteLine("clearing StringArray");
  441. this.stringArrayArgSet = null;
  442. parent.AddChild(this);
  443. Monitoring.Log(Monitoring.Provider.Process,
  444. (ushort)ProcessEvent.CreateUserProcess, 0,
  445. (uint)this.ProcessId, (uint)parent.ProcessId,
  446. 0, 0, 0);
  447. }
  448. public Process(Process parent,
  449. IoMemory rawImage,
  450. String role,
  451. String[] args,
  452. Manifest appManifest)
  453. : this(parent)
  454. {
  455. this.imageName = appManifest.Name;
  456. this.args = args;
  457. #if PAGING
  458. if (RunInSeparateSpace()) {
  459. bool kernelMode;
  460. string domainName = GetGroupFromName(this.imageName, out kernelMode);
  461. if (domainName != null) {
  462. this.protectionDomain = ProtectionDomain.FindOrCreateByName(domainName, kernelMode);
  463. }
  464. }
  465. #endif
  466. if (this.protectionDomain == null) {
  467. // Just inherit from our parent
  468. this.protectionDomain = parent.protectionDomain;
  469. }
  470. protectionDomain.AddRef();
  471. #if PAGING
  472. try {
  473. // Temporarily switch to the domain of the process
  474. // we are creating
  475. Thread.SwitchToDomain(this.protectionDomain);
  476. this.protectionDomain.InitHook(); // we might be first
  477. #endif
  478. Kernel.Waypoint(510);
  479. // this is a normal load (for BSP), so
  480. // set the 4th argument (isForMp) to false
  481. this.image = PEImage.Load(this, rawImage, out loadedImage,
  482. false);
  483. Monitoring.Log(Monitoring.Provider.Process,
  484. (ushort)ProcessEvent.ImageLoad,
  485. imageName);
  486. Kernel.Waypoint(511);
  487. // Trap-door to turn off debugger notification for micro-benchmark.
  488. if (args.Length > 0) {
  489. if (args[args.Length-1] == "!") {
  490. silentLoad = true;
  491. }
  492. else if (args[args.Length-1] == "!+") {
  493. DebugStub.WriteLine();
  494. DebugStub.WriteLine("*** Disabled debugger load notifications. Type \".reload\" to retrieve full symbols.");
  495. DebugStub.WriteLine();
  496. systemSilentLoad = true;
  497. }
  498. else if (args[args.Length-1] == "!-") {
  499. DebugStub.WriteLine();
  500. DebugStub.WriteLine("*** Enabled debugger load notifications.");
  501. DebugStub.WriteLine();
  502. systemSilentLoad = false;
  503. }
  504. }
  505. if (!silentLoad && systemSilentLoad) {
  506. silentLoad = true;
  507. }
  508. #if DEBUG
  509. DebugStub.WriteLine(
  510. "Loading {0} [{1:x}...{2:x} bytes]",
  511. __arglist(imageName,
  512. loadedImage.VirtualAddress,
  513. loadedImage.VirtualAddress + loadedImage.Length));
  514. #endif
  515. DebugStub.WriteLine(
  516. "Loaded process \"{0}\" into {1}protection domain \"{2}\"",
  517. __arglist(this.imageName,
  518. this.protectionDomain.KernelMode ? "kernel " : "",
  519. this.protectionDomain.Name));
  520. DebugStub.LoadedBinary(loadedImage.VirtualAddress,
  521. (UIntPtr) loadedImage.Length,
  522. imageName,
  523. image.checkSum,
  524. image.timeDateStamp,
  525. silentLoad);
  526. Kernel.Waypoint(512);
  527. threads[0] = Thread.CreateThread(this, new ThreadStart(this.PeStart));
  528. Kernel.Waypoint(513);
  529. #if PAGING
  530. }
  531. finally {
  532. Thread.RevertToParentDomain();
  533. }
  534. #endif
  535. // create the principal of the process
  536. #if APPLY_TPM
  537. this.principal = PrincipalImpl.NewInvocation(parent.Principal, appManifest, role, rawImage);
  538. #else
  539. this.principal = PrincipalImpl.NewInvocation(parent.Principal, appManifest, role, null);
  540. #endif
  541. Tracing.Log(Tracing.Audit, "Created PE process at {0:x8}",
  542. loadedImage.VirtualAddress);
  543. }
  544. public static Process KernelProcess
  545. {
  546. [NoHeapAllocation]
  547. get { return kernelProcess; }
  548. }
  549. public int ProcessId
  550. {
  551. [NoHeapAllocation]
  552. get { return processIndex; }
  553. }
  554. public Principal Principal
  555. {
  556. [NoHeapAllocation]
  557. get { return this.principal; }
  558. }
  559. public uint ProcessTag
  560. {
  561. [NoHeapAllocation]
  562. get { return processTag; }
  563. }
  564. public IoConfig IoConfig
  565. {
  566. [NoHeapAllocation]
  567. get { return ioconfig; }
  568. [NoHeapAllocation]
  569. set { ioconfig = value; }
  570. }
  571. public SharedHeap ProcessSharedHeap
  572. {
  573. [Inline]
  574. #if PAGING
  575. get { return protectionDomain.UserSharedHeap; }
  576. #else
  577. // Everyone uses the same heap
  578. get { return SharedHeap.KernelSharedHeap; }
  579. #endif
  580. }
  581. public ProtectionDomain Domain
  582. {
  583. get {
  584. return protectionDomain;
  585. }
  586. }
  587. #if PAGING
  588. public bool RunsAtKernelPrivilege {
  589. get {
  590. return protectionDomain.KernelMode;
  591. }
  592. }
  593. #else
  594. public bool RunsAtKernelPrivilege {
  595. get {
  596. // All processes run at ring-0 on
  597. // the non-PAGING build
  598. return true;
  599. }
  600. }
  601. #endif
  602. // Routines to maintain child process list.
  603. //
  604. // Called when a child process object is allocated (not called when
  605. // a child Process starts).
  606. private void AddChild(Process child)
  607. {
  608. Kernel.Waypoint(514);
  609. processMutex.AcquireMutex();
  610. try {
  611. for (int i = 0; i < children.Length; i++) {
  612. if (children[i] == null) {
  613. children[i] = child;
  614. return;
  615. }
  616. }
  617. // Grow array if necessary
  618. Process[] nc = new Process[children.Length * 2];
  619. for (int i = 0; i < children.Length; i++) {
  620. nc[i] = children[i];
  621. }
  622. nc[children.Length] = child;
  623. children = nc;
  624. }
  625. finally {
  626. processMutex.ReleaseMutex();
  627. }
  628. }
  629. // Should only be called from the kernel service thread.
  630. private bool ServiceRemoveChild(Process child)
  631. {
  632. Kernel.Waypoint(515);
  633. processMutex.AcquireMutex();
  634. try {
  635. for (int i = 0; i < children.Length; i++) {
  636. if (children[i] == child) {
  637. children[i] = null;
  638. if (child.wasStarted) {
  639. startedChildCount--;
  640. }
  641. return true;
  642. }
  643. }
  644. }
  645. finally {
  646. processMutex.ReleaseMutex();
  647. }
  648. return false;
  649. }
  650. // Routines to maintain child thread list.
  651. //
  652. // Called when a thread is created (not when a thread
  653. // is started)
  654. internal void AddThread(Thread thread, bool needThreadHandle)
  655. {
  656. Kernel.Waypoint(516);
  657. processMutex.AcquireMutex();
  658. try {
  659. VTable.Assert(thread.threadHandle.id == UIntPtr.Zero);
  660. if (needThreadHandle) {
  661. thread.threadHandle = new ThreadHandle(AllocateHandle(thread));
  662. }
  663. for (int i = 0; i < threads.Length; i++) {
  664. if (threads[i] == null) {
  665. threads[i] = thread;
  666. return;
  667. }
  668. }
  669. // Grow array if necessary
  670. Thread[] nc = new Thread[threads.Length * 2];
  671. for (int i = 0; i < threads.Length; i++) {
  672. nc[i] = threads[i];
  673. }
  674. nc[threads.Length] = thread;
  675. threads = nc;
  676. }
  677. finally {
  678. processMutex.ReleaseMutex();
  679. }
  680. }
  681. // Should be called only by the service thread
  682. private bool ServiceRemoveThread(Thread thread)
  683. {
  684. Kernel.Waypoint(517);
  685. processMutex.AcquireMutex();
  686. try {
  687. for (int i = 0; i < threads.Length; i++) {
  688. if (threads[i] == thread) {
  689. threads[i] = null;
  690. if (thread.ThreadState !=
  691. System.Threading.ThreadState.Unstarted) {
  692. Interlocked.Decrement(ref startedThreadCount);
  693. }
  694. return true;
  695. }
  696. }
  697. }
  698. finally {
  699. processMutex.ReleaseMutex();
  700. }
  701. return false;
  702. }
  703. public bool CreateThread(ThreadStart start)
  704. {
  705. Thread thread = Thread.CreateThread(this, new ThreadStart(start));
  706. if (thread == null) {
  707. Tracing.Log(Tracing.Audit, "Failed CreateThread request too late.");
  708. return false;
  709. }
  710. VTable.Assert(thread.threadHandle.id == UIntPtr.Zero);
  711. unchecked {
  712. Tracing.Log(Tracing.Audit, "Created new PE thread {1:x3}.",
  713. (UIntPtr)unchecked((uint)thread.threadIndex));
  714. }
  715. return true;
  716. }
  717. public unsafe bool CreateThread(int threadIndex,
  718. out ThreadHandle handle,
  719. out UIntPtr threadContext)
  720. {
  721. Thread thread =
  722. Thread.CreateThread(this, new ThreadStart(this.PeStartThread), true);
  723. if (thread != null) {
  724. VTable.Assert(thread.threadHandle.id != UIntPtr.Zero);
  725. thread.processThreadIndex = threadIndex;
  726. handle = thread.threadHandle;
  727. fixed (void *contextAddr = &thread.context) {
  728. threadContext = (UIntPtr) contextAddr;
  729. }
  730. }
  731. else {
  732. handle = new ThreadHandle();
  733. threadContext = 0;
  734. Tracing.Log(Tracing.Audit, "Failed CreateThread lid={0:x3}.",
  735. (UIntPtr)unchecked((uint)threadIndex));
  736. return false;
  737. }
  738. unchecked {
  739. Tracing.Log(Tracing.Audit, "Created new PE thread tid={0:x3}, lid={1:x3}.",
  740. (UIntPtr)unchecked((uint)thread.threadIndex),
  741. (UIntPtr)unchecked((uint)threadIndex));
  742. }
  743. return true;
  744. }
  745. // Should only be called from the kernel service thread.
  746. private void ServiceRelease()
  747. {
  748. Kernel.Waypoint(521);
  749. processMutex.AcquireMutex();
  750. try {
  751. if (state == ProcessState.Stopped) {
  752. return;
  753. }
  754. state = ProcessState.Stopped;
  755. }
  756. finally {
  757. processMutex.ReleaseMutex();
  758. }
  759. // Clear out any unstarted children and threads
  760. processMutex.AcquireMutex();
  761. Process[] childArray = children;
  762. Thread[] threadArray = threads;
  763. processMutex.ReleaseMutex();
  764. foreach (Process c in childArray) {
  765. if (c != null) {
  766. VTable.Assert(c.state == ProcessState.Unstarted);
  767. c.ServiceRelease();
  768. }
  769. }
  770. foreach (Thread t in threadArray) {
  771. if (t != null) {
  772. VTable.Assert(t.ThreadState
  773. == System.Threading.ThreadState.Unstarted);
  774. t.ServiceStopped();
  775. }
  776. }
  777. // Remove ourself
  778. bool found = parent.ServiceRemoveChild(this);
  779. VTable.Assert(found);
  780. VTable.Assert(processIndex >= 0);
  781. Kernel.Waypoint(522);
  782. // Set processIndex to -1 so that we don't race with GC
  783. // (see VisitSpecialData)
  784. int cachedProcessIndex = this.processIndex;
  785. this.processIndex = -1;
  786. UIntPtr imageBytes = UIntPtr.Zero;
  787. UIntPtr handleBytes;
  788. UIntPtr pageBytes;
  789. // Must switch to the target process' address space
  790. // to free memory properly
  791. #if PAGING
  792. try {
  793. Thread.SwitchToDomain(this.protectionDomain);
  794. #endif
  795. if (loadedImage != null) {
  796. imageBytes = (UIntPtr)loadedImage.Length;
  797. Tracing.Log(Tracing.Debug, "UnloadingBinary at {0:x8}",
  798. loadedImage.VirtualAddress);
  799. Kernel.Waypoint(523);
  800. DebugStub.UnloadedBinary(loadedImage.VirtualAddress, silentLoad);
  801. Kernel.Waypoint(524);
  802. IoMemory.Release(this, loadedImage);
  803. loadedImage = null;
  804. image = null;
  805. entry = null;
  806. }
  807. Kernel.Waypoint(525);
  808. handleBytes = handles.FreeAllPages();
  809. Controller.GetSystemController().UnRegisterController(cachedProcessIndex);
  810. Kernel.Waypoint(526);
  811. pageBytes = Memory.MemoryManager.FreeProcessMemory(this);
  812. Kernel.Waypoint(527);
  813. #if PAGING
  814. }
  815. finally {
  816. Thread.RevertToParentDomain();
  817. }
  818. #endif
  819. Tracing.Log(Tracing.Audit, "Memory: [image={0:x}, pages={1:x}, max={2:x}, handles={3:x}] total = {4} bytes",
  820. imageBytes, pageBytes, pagesMax, handleBytes,
  821. imageBytes + pageBytes + handleBytes);
  822. PrincipalImpl.Dispose(principal);
  823. // This must follow handles.FreeAllPages, which relies on processTag.
  824. // If we null out the entry earlier then the tag could be
  825. // reused and handles.FreeAllPages could free another process's memory
  826. processTable[cachedProcessIndex] = null;
  827. joinEvent.Set();
  828. SharedHeapWalker.walker.RequestWalk();
  829. parent.ServiceCheckForExit();
  830. #if PAGING
  831. // Release our enclosing protection domain
  832. protectionDomain.Release();
  833. #endif
  834. #if false
  835. DebugStub.WriteLine(
  836. "Memory: [image={0:x8}, pages={1:x8}, maxpages={2:x8}, " +
  837. "handles={3:x8}] total={4:x8} bytes\n",
  838. __arglist(
  839. imageBytes,
  840. pageBytes,
  841. pagesMax,
  842. handleBytes,
  843. (long)(imageBytes + pageBytes + handleBytes)));
  844. #endif
  845. }
  846. internal unsafe bool CheckEndpointsSet ()
  847. {
  848. if (endpointSet == null) return true;
  849. for (int i = 0; i < endpointSet.Length; i++) {
  850. if (endpointSet[i] == null) {
  851. DebugStub.WriteLine("Process.Start: Cannot start process (id {0}, image {1}), because endpoint {2} is not set",
  852. __arglist(processIndex, imageName, i));
  853. return false;
  854. }
  855. }
  856. return true;
  857. }
  858. // Start the process.
  859. public bool Start()
  860. {
  861. // If we're to be suspended, wait until after resumption to start
  862. // other processes.
  863. SuspendBarrierCheckParents();
  864. processMutex.AcquireMutex();
  865. parent.processMutex.AcquireMutex();
  866. try {
  867. if (state != ProcessState.Unstarted) {
  868. DebugStub.WriteLine(" process not in unstarted state!\n");
  869. return false;
  870. }
  871. if (!CheckEndpointsSet()) {
  872. return false;
  873. }
  874. parent.startedChildCount++;
  875. state = ProcessState.Running;
  876. wasStarted = true;
  877. threads[0].SetMainThreadRunning();
  878. }
  879. finally {
  880. parent.processMutex.ReleaseMutex();
  881. processMutex.ReleaseMutex();
  882. }
  883. Kernel.Waypoint(528);
  884. threads[0].StartRunningThread();
  885. Kernel.Waypoint(529);
  886. return true;
  887. }
  888. internal void StartThread()
  889. {
  890. // If we're being suspended, wait until after resumption to start.
  891. SuspendBarrier();
  892. // Increment number of threads in a process and continue
  893. Interlocked.Increment (ref this.startedThreadCount);
  894. }
  895. // precondition: processMutex held
  896. internal void StartMainThread()
  897. {
  898. VTable.Assert(state == ProcessState.Running);
  899. VTable.Assert(startedThreadCount == 0);
  900. startedThreadCount++;
  901. }
  902. // started==true indicates a started process; false
  903. // indicates an unstarted process.
  904. public void Join(out bool started)
  905. {
  906. Join(SchedulerTime.MaxValue, out started);
  907. }
  908. public void Join()
  909. {
  910. bool started;
  911. Join(out started);
  912. if (!started) {
  913. throw new ProcessStateException("joining unstarted process");
  914. }
  915. }
  916. // started==true indicates a started process; false
  917. // indicates an unstarted process.
  918. // Returns false if the join timed out, true otherwise.
  919. public bool Join(TimeSpan timeout, out bool started)
  920. {
  921. return Join(SchedulerTime.Now + timeout, out started);
  922. }
  923. // started==true indicates a started process; false
  924. // indicates an unstarted process.
  925. // Returns false if the join timed out, true otherwise.
  926. public bool Join(SchedulerTime timeOut, out bool started)
  927. {
  928. if (state == ProcessState.Unstarted) {
  929. started = false;
  930. return false;
  931. }
  932. started = true;
  933. return joinEvent.WaitOne(timeOut);
  934. }
  935. // Freeze all the threads in a process. If recursive==true, then
  936. // freeze all threads in all descendant processes as well. This
  937. // method blocks until all freezing is complete. Before a thread
  938. // in kernel mode is frozen, it is allowed to run until it reaches
  939. // a blocking operation, until it exits, or until it enters process
  940. // mode. Semantically, suspended thread execution should be
  941. // equivalent to running thread execution, except that suspended
  942. // threads appear to receive time slices of length 0.
  943. // Returns true if successful; returns false to indicate an
  944. // unstarted process.
  945. public bool Suspend(bool recursive)
  946. {
  947. // Ask the kernel service thread to call ServiceSuspend.
  948. return ThreadLocalServiceRequest.SuspendProcess(this, recursive);
  949. }
  950. // Should only execute in the kernel service thread
  951. internal bool ServiceSuspend(bool recursive)
  952. {
  953. return ServiceSuspend(recursive, false);
  954. }
  955. // Should only execute in the kernel service thread
  956. private bool ServiceSuspend(bool recursive, bool aboutToStop)
  957. {
  958. bool alreadySuspended = false;
  959. processMutex.AcquireMutex();
  960. try {
  961. // The service thread should not already be in the middle of an operation:
  962. Debug.Assert(state != ProcessState.Suspending, "unexpected process state");
  963. Debug.Assert(state != ProcessState.SuspendingRecursive, "unexpected process state");
  964. Debug.Assert(state != ProcessState.Stopping, "unexpected process state");
  965. if (state == ProcessState.Running) {
  966. state = (recursive)?(ProcessState.SuspendingRecursive):(ProcessState.Suspending);
  967. }
  968. else if (!aboutToStop && state == ProcessState.Unstarted) {
  969. return false;
  970. }
  971. else {
  972. alreadySuspended = true;
  973. }
  974. }
  975. finally {
  976. processMutex.ReleaseMutex();
  977. }
  978. if (!alreadySuspended) {
  979. // Hold suspendMutex until suspension is complete, so that other
  980. // threads in this process block when acquiring suspendMutex.
  981. // Only try to acquire suspendMutex if the process isn't already
  982. // suspended, though -- otherwise, one of the suspended threads
  983. // might be holding suspendMutex.
  984. suspendMutex.AcquireMutex();
  985. }
  986. if (recursive) {
  987. // Note: now that this.state==Suspending[Recursive], a barrier
  988. // prevents new child processes, so we can safely traverse the
  989. // existing children without missing any.
  990. for (int index = 0;; index++) {
  991. Process child = null;
  992. processMutex.AcquireMutex();
  993. try {
  994. if (index >= children.Length) {
  995. break;
  996. }
  997. else if (children[index] == null) {
  998. continue;
  999. }
  1000. child = children[index];
  1001. }
  1002. finally {
  1003. processMutex.ReleaseMutex();
  1004. }
  1005. if (child != null) {
  1006. child.ServiceSuspend(true, aboutToStop);
  1007. }
  1008. }
  1009. }
  1010. if (alreadySuspended) {
  1011. // This process is already suspended, the children are
  1012. // suspended (if recursive==true), so we're done.
  1013. return true;
  1014. }
  1015. bool yieldAndRepeat;
  1016. do {
  1017. yieldAndRepeat = false;
  1018. // Note: now that this.state==Suspending[Recursive], a barrier
  1019. // prevents starting threads, so we can safely traverse the
  1020. // existing threads without missing any started threads.
  1021. for (int index = 0;; index++) {
  1022. Thread thread = null;
  1023. processMutex.AcquireMutex();
  1024. try {
  1025. if (index >= threads.Length) {
  1026. break;
  1027. }
  1028. else if (threads[index] == null) {
  1029. continue;
  1030. }
  1031. thread = threads[index];
  1032. }
  1033. finally {
  1034. processMutex.ReleaseMutex();
  1035. }
  1036. if (thread != null) {
  1037. thread.Suspend(aboutToStop);
  1038. }
  1039. }
  1040. if (yieldAndRepeat) {
  1041. Thread.Yield();
  1042. }
  1043. } while (yieldAndRepeat);
  1044. processMutex.AcquireMutex();
  1045. state = ProcessState.Suspended;
  1046. processMutex.ReleaseMutex();
  1047. suspendMutex.ReleaseMutex();
  1048. return true;
  1049. }
  1050. // Returns true if successful; returns false to indicate an
  1051. // unstarted process.
  1052. public bool Resume(bool recursive)
  1053. {
  1054. // Ask the kernel service thread to call ServiceResume.
  1055. return ThreadLocalServiceRequest.ResumeProcess(this, recursive);
  1056. }
  1057. // Should only execute in the kernel service thread
  1058. internal bool ServiceResume(bool recursive)
  1059. {
  1060. bool alreadyResumed = false;
  1061. processMutex.AcquireMutex();
  1062. try {
  1063. // The service thread should not already be in the middle of an operation:
  1064. Debug.Assert(state != ProcessState.Suspending, "unexpected process state");
  1065. Debug.Assert(state != ProcessState.SuspendingRecursive, "unexpected process state");
  1066. Debug.Assert(state != ProcessState.Stopping, "unexpected process state");
  1067. if (state == ProcessState.Suspended) {
  1068. state = ProcessState.Running;
  1069. }
  1070. else if (state == ProcessState.Unstarted) {
  1071. return false;
  1072. }
  1073. else {
  1074. alreadyResumed = true;
  1075. }
  1076. }
  1077. finally {
  1078. processMutex.ReleaseMutex();
  1079. }
  1080. if (recursive) {
  1081. for (int index = 0;; index++) {
  1082. Process child = null;
  1083. processMutex.AcquireMutex();
  1084. try {
  1085. if (index >= children.Length) {
  1086. break;
  1087. }
  1088. else if (children[index] == null) {
  1089. continue;
  1090. }
  1091. child = children[index];
  1092. }
  1093. finally {
  1094. processMutex.ReleaseMutex();
  1095. }
  1096. if (child != null) {
  1097. child.ServiceResume(true);
  1098. }
  1099. }
  1100. }
  1101. if (alreadyResumed) {
  1102. // This process is already resumed, the children are
  1103. // resumed (if recursive==true), so we're done.
  1104. return true;
  1105. }
  1106. for (int index = 0;; index++) {
  1107. Thread thread = null;
  1108. processMutex.AcquireMutex();
  1109. try {
  1110. if (index >= threads.Length) {
  1111. break;
  1112. }
  1113. else if (threads[index] == null) {
  1114. continue;
  1115. }
  1116. thread = threads[index];
  1117. }
  1118. finally {
  1119. processMutex.ReleaseMutex();
  1120. }
  1121. if (thread != null) {
  1122. thread.Resume();
  1123. }
  1124. }
  1125. return true;
  1126. }
  1127. public void Stop(int exitCode)
  1128. {
  1129. //
  1130. // Terminate the process forcefully.
  1131. // Should remove all user code from threads, then force them
  1132. // to terminate ASAP, close out objects, etc.
  1133. // Ask the kernel service thread to call ServiceStop.
  1134. ThreadLocalServiceRequest.StopProcess(this, exitCode);
  1135. }
  1136. // Should only execute in the kernel service thread
  1137. //
  1138. // ServiceStop does not block waiting for threads to exit,
  1139. // so it is recommended that whoever makes the service
  1140. // request (currently ThreadLocalServiceRequest) perform
  1141. // a Process.Join to block until the threads have exited
  1142. // and the process has stopped.
  1143. internal void ServiceStop(int exitCode)
  1144. {
  1145. processMutex.AcquireMutex();
  1146. try {
  1147. if (state == ProcessState.Stopped) {
  1148. return;
  1149. }
  1150. }
  1151. finally {
  1152. processMutex.ReleaseMutex();
  1153. }
  1154. // Make sure that any suspended process we're about to stop has
  1155. // a chance to process any pending signals before getting stopped
  1156. // forever:
  1157. ServiceResume(true);
  1158. // Now suspend it for good:
  1159. ServiceSuspend(true, true);
  1160. ServiceStopAfterSuspend(exitCode);
  1161. }
  1162. // Should only execute in the kernel service thread
  1163. private void ServiceStopAfterSuspend(int exitCode)
  1164. {
  1165. processMutex.AcquireMutex();
  1166. try {
  1167. // Note: we cannot be "Stopped" here, because there
  1168. // are no calls to ServiceRelease between here and
  1169. // the beginning of ServiceStop. If we ever decide to have
  1170. // more than one service thread, we'll have to revisit this.
  1171. Debug.Assert(state == ProcessState.Suspended
  1172. || state == ProcessState.Unstarted, "unexpected process state");
  1173. state = ProcessState.Stopping;
  1174. }
  1175. finally {
  1176. processMutex.ReleaseMutex();
  1177. }
  1178. processMutex.AcquireMutex();
  1179. Process[] childArray = children;
  1180. processMutex.ReleaseMutex();
  1181. // Don't hold processMutex while calling ServiceStop; it
  1182. // would try to double-acquire the lock in RemoveChild.
  1183. // No locking should be necessary here, because a
  1184. // suspended process should not add new children.
  1185. foreach (Process c in childArray) {
  1186. if (c != null) {
  1187. c.ServiceStopAfterSuspend(exitCode);
  1188. }
  1189. }
  1190. // Throw an exception in each suspended thread.
  1191. for (int index = 0;; index++) {
  1192. Thread thread = null;
  1193. processMutex.AcquireMutex();
  1194. try {
  1195. if (index >= threads.Length) {
  1196. break;
  1197. }
  1198. else if (threads[index] == null) {
  1199. continue;
  1200. }
  1201. thread = threads[index];
  1202. }
  1203. finally {
  1204. processMutex.ReleaseMutex();
  1205. }
  1206. if (thread != null) {
  1207. thread.StopSuspended();
  1208. }
  1209. }
  1210. if (exitCode >= (int) ProcessExitCode.StopMin &&
  1211. exitCode <= (int) ProcessExitCode.StopMax) {
  1212. this.exitCode = exitCode;
  1213. }
  1214. else {
  1215. this.exitCode = (int) ProcessExitCode.StopDefault;
  1216. }
  1217. // Needed only to handle the Unstarted state:
  1218. ServiceCheckForExit();
  1219. }

Large files files are truncated, but you can click here to view the full file