PageRenderTime 30ms CodeModel.GetById 27ms 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
  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. }
  1220. // Should only execute in the kernel service thread
  1221. internal void ServiceOnThreadStop(Thread thread)
  1222. {
  1223. #if THREAD_TIME_ACCOUNTING
  1224. deadThreadExecutionTime += thread.ExecutionTime;
  1225. deadThreadCount++;
  1226. #endif
  1227. bool found = ServiceRemoveThread(thread);
  1228. VTable.Assert(found);
  1229. ServiceCheckForExit();
  1230. }
  1231. // Check to see if a process should exit. If so, release its
  1232. // resources.
  1233. // Should only execute in the kernel service thread
  1234. private void ServiceCheckForExit()
  1235. {
  1236. if (startedThreadCount == 0 && startedChildCount == 0) {
  1237. ServiceRelease();
  1238. }
  1239. }
  1240. // If the current process is about to suspend, block until
  1241. // the process resumes. Note: if efficiency is more important than
  1242. // immediate blocking, you can check ThreadContext.suspendAlert
  1243. // before calling SuspendBarrier, which (assuming a reasonable
  1244. // multiprocessor memory model) will eventually become
  1245. // true during a suspension if the thread runs long enough:
  1246. // if (Thread.CurrentThread.context.suspendAlert) SuspendBarrier();
  1247. // The important thing is that each running thread eventually enters a
  1248. // suspendable state (process-unblocked-running or
  1249. // kernel-blocked-running) so that the loop in ServiceSuspend will
  1250. // terminate.
  1251. internal static void SuspendBarrier()
  1252. {
  1253. Process p = Thread.CurrentProcess;
  1254. // The service thread holds the suspendMutex throughout the
  1255. // suspension process, so we'll block if we try to acquire
  1256. // it during suspension:
  1257. p.suspendMutex.AcquireMutex();
  1258. Thread.CurrentThread.context.suspendAlert = false;
  1259. // Ok, we must be running now. Release the mutex.
  1260. p.suspendMutex.ReleaseMutex();
  1261. }
  1262. // Block if any the current process is suspending or if any of its
  1263. // ancestors is known by this processor to be suspending recursively.
  1264. internal static void SuspendBarrierCheckParents()
  1265. {
  1266. bool yieldAndRepeat;
  1267. do {
  1268. yieldAndRepeat = false;
  1269. SuspendBarrier();
  1270. for (Process p = Thread.CurrentProcess.parent; p != null; p = p.parent) {
  1271. // Don't try to acquire another process's suspendMutex;
  1272. // instead, just check its state field.
  1273. // MULTIPROCESSOR NOTE: It's not
  1274. // important that we see the most up-to-date value of
  1275. // p.state immediately -- we just need to see
  1276. // SuspendingRecursive eventually if we call this
  1277. // barrier enough times.
  1278. if (p.state == ProcessState.SuspendingRecursive) {
  1279. // An ancestor is suspending recursively. This
  1280. // means we'll be suspended soon. Just wait
  1281. // for this to happen by yielding repeatedly;
  1282. // we'll eventually block in SuspendBarrier().
  1283. yieldAndRepeat = true;
  1284. }
  1285. }
  1286. if (yieldAndRepeat) {
  1287. Thread.Yield();
  1288. }
  1289. } while (yieldAndRepeat);
  1290. }
  1291. public void Allocated(UIntPtr bytes)
  1292. {
  1293. #if THREAD_SAFE_INTERNAL_ONLY
  1294. UIntPtr used;
  1295. UIntPtr now;
  1296. do {
  1297. now = pagesNow;
  1298. used = now + bytes;
  1299. } while (now != Interlocked.CompareExchange(ref pagesNow, used, now));
  1300. do {
  1301. now = pagesMax;
  1302. } while (used > now &&
  1303. now != Interlocked.CompareExchange(ref pagesMax, used, now));
  1304. #else
  1305. pagesNow += bytes;
  1306. if (pagesMax < pagesNow) {
  1307. pagesMax = pagesNow;
  1308. }
  1309. #endif
  1310. }
  1311. public void Freed(UIntPtr bytes)
  1312. {
  1313. #if THREAD_SAFE_INTERNAL_ONLY
  1314. UIntPtr used;
  1315. UIntPtr now;
  1316. do {
  1317. now = pagesNow;
  1318. used = now - bytes;
  1319. } while (now != Interlocked.CompareExchange(ref pagesNow, used, now));
  1320. #else
  1321. pagesNow -= bytes;
  1322. #endif
  1323. }
  1324. // Returns the currently allocated memory in bytes.
  1325. public UIntPtr AllocatedMemory {
  1326. [NoHeapAllocation]
  1327. get { return pagesNow; }
  1328. }
  1329. // Returns the peak allocated memory in bytes.
  1330. public UIntPtr PeakAllocatedMemory {
  1331. [NoHeapAllocation]
  1332. get { return pagesMax; }
  1333. }
  1334. // Returns number of pages in the handle table
  1335. public int NumHandlePages {
  1336. [NoHeapAllocation]
  1337. get { return handles.GetPageCount(); }
  1338. }
  1339. public int ExitCode {
  1340. [NoHeapAllocation]
  1341. get { return exitCode; }
  1342. }
  1343. // Return parameter is really: DirectoryService.Imp opt(ExHeap) *
  1344. public unsafe SharedHeap.Allocation * GetNamespaceEndpoint()
  1345. {
  1346. return DirectoryService.NewClientEndpointEx();
  1347. }
  1348. //
  1349. // Endpoint Argument Processing
  1350. //
  1351. // Set the size of the endpoint set.
  1352. public unsafe bool SetEndpointCount(int count) {
  1353. if (state != ProcessState.Unstarted) {
  1354. throw new ProcessStateException("process not unstarted");
  1355. }
  1356. if (count == 0) {
  1357. // don't create array if the count is zero.
  1358. return true;
  1359. }
  1360. endpointSet = new SharedHeap.Allocation * [count];
  1361. //DebugStub.WriteLine("-- Process.SetEndpointCount({0})",
  1362. //__arglist(count));
  1363. return true;
  1364. }
  1365. // Set the endpoint and individual endpoint.
  1366. public unsafe bool SetEndpoint(int index, ref SharedHeap.Allocation * endpoint)
  1367. {
  1368. // TODO: FIXFIX: I short-circuited the check below to bypass
  1369. // issues with stdin pipes.
  1370. // if (state != ProcessState.Unstarted) {
  1371. // throw new ProcessStateException("process not unstarted");
  1372. //
  1373. if (endpointSet == null) {
  1374. DebugStub.WriteLine("Process.SetEndpoint is NULL!");
  1375. throw new ProcessStateException("endpoint set not allocated, attempting to set");
  1376. }
  1377. if (index > endpointSet.Length - 1) {
  1378. DebugStub.WriteLine("Process.SetEndpoint {0} out of range!",__arglist(index));
  1379. throw new ProcessStateException("endpoint index out of range");
  1380. }
  1381. if (endpointSet[index] != null) {
  1382. DebugStub.Break();
  1383. DebugStub.WriteLine("Process.SetEndpoint {0} was already set!",__arglist(index));
  1384. throw new ProcessStateException("endpoint already non-null");
  1385. }
  1386. // We first move it to the kernel. When the target process retrieves it,
  1387. // we move it into its heap.
  1388. endpointSet[index] =
  1389. Microsoft.Singularity.Channels.EndpointCore.MoveEndpoint(
  1390. Thread.CurrentProcess.ProcessSharedHeap,
  1391. SharedHeap.KernelSharedHeap, this, endpoint);
  1392. endpoint = null;
  1393. return true;
  1394. }
  1395. public unsafe int GetStartupEndpointCount()
  1396. {
  1397. //DebugStub.WriteLine("-- Process.GetStartupEndpointCount() -> {0}",
  1398. //__arglist((int)(endpointSet != null ? endpointSet.Length : 0)));
  1399. return endpointSet != null ? endpointSet.Length : 0;
  1400. }
  1401. public unsafe SharedHeap.Allocation * GetStartupEndpoint(int arg)
  1402. {
  1403. // Endpoints can only be retrieved once.
  1404. if (endpointSet == null || arg >= endpointSet.Length) {
  1405. // legacy code will always ask for a null endpoint 0.
  1406. //DebugStub.WriteLine("-- Process.GetStartupEndpoint({0}) -> {1:x8}",
  1407. //__arglist(arg, 0));
  1408. return null;
  1409. }
  1410. SharedHeap.Allocation * used = endpointSet[arg];
  1411. endpointSet[arg] = null;
  1412. #if PAGING
  1413. // now move it from kernel to user process
  1414. used = Microsoft.Singularity.Channels.EndpointCore.MoveEndpoint(
  1415. SharedHeap.KernelSharedHeap, this.ProcessSharedHeap, this, used);
  1416. #endif
  1417. return used;
  1418. }
  1419. // String Argument Processing
  1420. // <set,get>StringArg
  1421. // <set,get>StringArgCount
  1422. public bool SetStringArgCount(int count) {
  1423. if (state != ProcessState.Unstarted) {
  1424. throw new ProcessStateException("process not unstarted");
  1425. }
  1426. if (count == 0) {
  1427. // don't create array if the count is zero.
  1428. return true;
  1429. }
  1430. stringArgSet = new StringArg [count];
  1431. //DebugStub.WriteLine("-- Process.SetStringArgCount({0})",
  1432. //__arglist(count));
  1433. return true;
  1434. }
  1435. public bool SetStringArrayArgCount(int count) {
  1436. //DebugStub.WriteLine("SetStringArrayArg called. count={0}", __arglist(count));
  1437. if (state != ProcessState.Unstarted) {
  1438. throw new ProcessStateException("process not unstarted");
  1439. }
  1440. if (count == 0) {
  1441. // don't create array if the count is zero.
  1442. return true;
  1443. }
  1444. stringArrayArgSet = new StringArrayArg [count];
  1445. if (stringArrayArgSet == null) {
  1446. throw new Exception("out of memory in process SetStringArrayArgCount");
  1447. }
  1448. return true;
  1449. }
  1450. public int GetStartupStringArrayArgCount() {
  1451. return stringArrayArgSet != null ? stringArrayArgSet.Length : 0;
  1452. }
  1453. public ParameterCode GetStartupStringArrayArg(int index, out string [] strings)
  1454. {
  1455. //DebugStub.WriteLine("GetStartupStringArrayArg called. index={0}", __arglist(index));
  1456. if (stringArrayArgSet == null) {
  1457. strings = null;
  1458. return ParameterCode.NotSet;
  1459. }
  1460. if (index > stringArrayArgSet.Length - 1) {
  1461. strings = null;
  1462. return ParameterCode.OutOfRange;
  1463. }
  1464. if (stringArrayArgSet[index] == null) {
  1465. strings = null;
  1466. return ParameterCode.NotSet;
  1467. }
  1468. if (!stringArrayArgSet[index].Set) {
  1469. strings = null;
  1470. return ParameterCode.NotSet;
  1471. }
  1472. //DebugStub.WriteLine("GetStartupStringArrayArg getting value");
  1473. strings = stringArrayArgSet[index].Value;
  1474. return ParameterCode.Success;
  1475. }
  1476. public ParameterCode SetStartupStringArrayArg(int index, string[] strings)
  1477. {
  1478. //DebugStub.WriteLine("Setting string Arg array");
  1479. if (index > stringArrayArgSet.Length - 1) {
  1480. return ParameterCode.OutOfRange;
  1481. }
  1482. if (stringArrayArgSet[index] == null) {
  1483. stringArrayArgSet[index] = new StringArrayArg(strings);
  1484. }
  1485. else {
  1486. stringArrayArgSet[index].Value = strings;
  1487. }
  1488. stringArrayArgSet[index].Set = true;
  1489. return ParameterCode.Success;
  1490. }
  1491. public ParameterCode SetStartupStringArg(int index, string value) {
  1492. //DebugStub.WriteLine("set string attempting to set idx={0}", __arglist(index));
  1493. if (index > stringArgSet.Length - 1) {
  1494. //DebugStub.WriteLine("Process.SetStringArg {0} out of range!",__arglist(index));
  1495. //throw new ProcessStateException("StringArg index out of range");
  1496. return ParameterCode.OutOfRange;
  1497. }
  1498. if (stringArgSet[index] != null) {
  1499. //DebugStub.Break();
  1500. //DebugStub.WriteLine("Process.SetStringArg {0} was already set!",__arglist(index));
  1501. //throw new ProcessStateException("StringArg already non-null");
  1502. return ParameterCode.AlreadySet;
  1503. }
  1504. stringArgSet[index] = new StringArg(value);
  1505. stringArgSet[index].Set = true;
  1506. return ParameterCode.Success;
  1507. }
  1508. public unsafe int GetStartupStringArgCount() {
  1509. return stringArgSet != null ? stringArgSet.Length : 0;
  1510. }
  1511. public unsafe ParameterCode GetStartupStringArg(int arg, out string value) {
  1512. if (stringArgSet == null) {
  1513. value = null;
  1514. return ParameterCode.NotSet;
  1515. }
  1516. if (arg >= stringArgSet.Length) {
  1517. value = null;
  1518. return ParameterCode.OutOfRange;
  1519. }
  1520. if (stringArgSet[arg] == null) {
  1521. value = null;
  1522. return ParameterCode.Success;
  1523. }
  1524. if (!stringArgSet[arg].Set) {
  1525. value = null;
  1526. return ParameterCode.NotSet;
  1527. }
  1528. value = stringArgSet[arg].Value;
  1529. return ParameterCode.Success;
  1530. }
  1531. // int Argument Processing
  1532. // <set,get>StringArg
  1533. // <set,get>StringArgCount
  1534. public unsafe bool SetLongArgCount(int count) {
  1535. if (state != ProcessState.Unstarted) {
  1536. throw new ProcessStateException("process not unstarted");
  1537. }
  1538. if (count == 0) {
  1539. // don't create array if the count is zero.
  1540. return true;
  1541. }
  1542. longArgSet = new LongArg [count];
  1543. //DebugStub.WriteLine("-- Process.SetLongArgCount({0})",
  1544. //__arglist(count));
  1545. return true;
  1546. }
  1547. public unsafe ParameterCode SetStartupLongArg(int index, long value) {
  1548. if (index > longArgSet.Length - 1) {
  1549. //DebugStub.WriteLine("Process.SetLongArg {0} out of range!",__arglist(index));
  1550. //throw new ProcessStateException("LongArg index out of range");
  1551. return ParameterCode.OutOfRange;
  1552. }
  1553. // TODO checks for setting more than once
  1554. if (longArgSet[index] != null) {
  1555. return ParameterCode.AlreadySet;
  1556. }
  1557. longArgSet[index] = new LongArg(value);
  1558. longArgSet[index].Set = true;
  1559. return ParameterCode.Success;
  1560. }
  1561. public unsafe int GetStartupLongArgCount() {
  1562. return longArgSet != null ? longArgSet.Length : 0;
  1563. }
  1564. public unsafe ParameterCode GetStartupLongArg(int arg, out long value) {
  1565. if (longArgSet == null || arg >= longArgSet.Length) {
  1566. //DebugStub.WriteLine("Process.GetLongArg {0} out of range!",__arglist(arg));
  1567. //throw new ProcessStateException("LongArg index out of range");
  1568. value = -1;
  1569. return ParameterCode.OutOfRange;
  1570. }
  1571. if (longArgSet[arg] == null) {
  1572. value = -1;
  1573. return ParameterCode.NotSet;
  1574. }
  1575. if (longArgSet[arg].Set == false) {
  1576. value = -1;
  1577. return ParameterCode.NotSet;
  1578. }
  1579. #if EXTRA
  1580. if (longArgSet[arg].Retrieved == true) {
  1581. value = -1;
  1582. return ParameterCode.Retrieved;
  1583. }
  1584. #endif
  1585. value = longArgSet[arg].Value;
  1586. longArgSet[arg].Retrieved = true;
  1587. return ParameterCode.Success;
  1588. }
  1589. // bool Argument Processing
  1590. // <set,get>StringArg
  1591. // <set,get>StringArgCount
  1592. public unsafe bool SetBoolArgCount(int count) {
  1593. if (state != ProcessState.Unstarted) {
  1594. throw new ProcessStateException("process not unstarted");
  1595. }
  1596. if (count == 0) {
  1597. // don't create array if the count is zero.
  1598. return true;
  1599. }
  1600. boolArgSet = new BoolArg [count];
  1601. //DebugStub.WriteLine("-- Process.SetBoolArgCount({0})",
  1602. //__arglist(boolArgSet.Length));
  1603. return true;
  1604. }
  1605. public unsafe ParameterCode SetStartupBoolArg(int index, bool value) {
  1606. if (boolArgSet == null) return ParameterCode.OutOfRange;
  1607. if (index > boolArgSet.Length - 1) {
  1608. //DebugStub.WriteLine("Process.SetBoolArg {0} out of range!",__arglist(index));
  1609. //throw new ProcessStateException("BoolArg index out of range");
  1610. return ParameterCode.OutOfRange;
  1611. }
  1612. // TODO checks for setting more than once
  1613. boolArgSet[index] = new BoolArg(value);
  1614. boolArgSet[index].Set = true;
  1615. return ParameterCode.Success;
  1616. }
  1617. public unsafe ParameterCode GetStartupBoolArg(int index, out bool value) {
  1618. value = false;
  1619. if (boolArgSet == null || index >= boolArgSet.Length) {
  1620. //DebugStub.WriteLine("Process.GetBoolArg {0} out of range!",__arglist(index));
  1621. //throw new ProcessStateException("BoolArg index out of range");\
  1622. value = false;
  1623. return ParameterCode.OutOfRange;
  1624. }
  1625. if (boolArgSet[index] == null) {
  1626. value = false;
  1627. return ParameterCode.NotSet;
  1628. }
  1629. if (boolArgSet[index].Set == false) {
  1630. return ParameterCode.NotSet;
  1631. }
  1632. value = boolArgSet[index].Value;
  1633. boolArgSet[index].Retrieved = true;
  1634. return ParameterCode.Success;
  1635. }
  1636. public unsafe int GetStartupBoolArgCount() {
  1637. //if ( boolArgSet != null) DebugStub.WriteLine("bool args=", __arglist(boolArgSet.Length));
  1638. return boolArgSet != null ? boolArgSet.Length : 0;
  1639. }
  1640. public void SetArgs(string[] args)
  1641. {
  1642. this.args = args;
  1643. }
  1644. [NoHeapAllocation]
  1645. public int GetStartupArgCount()
  1646. {
  1647. return args.Length;
  1648. }
  1649. [NoHeapAllocation]
  1650. public string GetStartupArg(int arg)
  1651. {
  1652. if (arg >= args.Length) {
  1653. return null;
  1654. }
  1655. return args[arg];
  1656. }
  1657. [NoHeapAllocation]
  1658. public string GetProcessName() {
  1659. return imageName;
  1660. }
  1661. [NoHeapAllocation]
  1662. public void SetGcPerformanceCounters(TimeSpan timeSpent, long bytes) {
  1663. gcCount++;
  1664. gcTotalTime = gcTotalTime.AddNoAlloc(timeSpent);
  1665. gcTotalBytes += bytes;
  1666. }
  1667. [NoHeapAllocation]
  1668. public void GetGcPerformanceCounters( out int count, out TimeSpan time, out long bytes)
  1669. {
  1670. count = gcCount;
  1671. time = gcTotalTime;
  1672. bytes = gcTotalBytes;
  1673. }
  1674. public long GetThreadTimes()
  1675. {
  1676. #if THREAD_TIME_ACCOUNTING
  1677. long total = 0;
  1678. for (int i = 0; i < threads.Length; i++) {
  1679. if (threads[i] != null) {
  1680. total += threads[i].ExecutionTime.Ticks;
  1681. }
  1682. }
  1683. return total;
  1684. #else
  1685. return 0;
  1686. #endif
  1687. }
  1688. public long DeadThreadCount
  1689. {
  1690. get
  1691. {
  1692. return deadThreadCount;
  1693. }
  1694. }
  1695. public long DeadThreadTime
  1696. {
  1697. get
  1698. {
  1699. return deadThreadExecutionTime.Ticks;
  1700. }
  1701. }
  1702. public int [] GetThreadIDs()
  1703. {
  1704. int threadCount = 0;
  1705. int [] temp = null;
  1706. processMutex.AcquireMutex();
  1707. try {
  1708. for (int i = 0; i < threads.Length; i++) {
  1709. if (threads[i] != null) threadCount++;
  1710. }
  1711. if (threadCount > 0) {
  1712. temp = new int[threadCount];
  1713. int current = 0;
  1714. for (int i = 0; i < threads.Length; i++) {
  1715. if (threads[i] != null) {
  1716. temp[current++] = threads[i].GetThreadId();
  1717. }
  1718. }
  1719. }
  1720. //else DebugStub.Break();
  1721. }
  1722. finally {
  1723. processMutex.ReleaseMutex();
  1724. }
  1725. return temp;
  1726. }
  1727. // Start the execution within the PE Image.
  1728. private void PeStart()
  1729. {
  1730. Tracing.Log(Tracing.Audit, "** Start of process {0}.", args[0]);
  1731. UIntPtr entryPoint = image.GetEntryPoint(loadedImage);
  1732. #if VERBOSE
  1733. DebugStub.WriteLine("calling CallEntryPoint");
  1734. DebugStub.WriteLine(" entry:{0:x8}, args{1}",__arglist((uint)entryPoint, args));
  1735. for (int i = 0; i < args.Length; i++) {
  1736. DebugStub.WriteLine(" {0}: [{1}]", __arglist(i, args[i]));
  1737. }
  1738. #endif
  1739. try {
  1740. Tracing.Log(Tracing.Audit, "Calling entryPoint={0:x}", entryPoint);
  1741. Kernel.Waypoint(530);
  1742. #if THREAD_TIME_ACCOUNTING
  1743. Processor.GetCurrentThread().context.lastExecutionTimeUpdate =
  1744. Processor.CycleCount;
  1745. #endif
  1746. int code = PEImage.CallEntryPoint(entryPoint, -1, !RunsAtKernelPrivilege);
  1747. if (code >= (int) ProcessExitCode.MainMin &&
  1748. code <= (int) ProcessExitCode.MainMax) {
  1749. exitCode = code;
  1750. }
  1751. else {
  1752. exitCode = (int) ProcessExitCode.ErrorDefault;
  1753. }
  1754. Kernel.Waypoint(531);
  1755. unchecked {
  1756. Tracing.Log(Tracing.Audit, "Main thread exited with (exit={0})",
  1757. (UIntPtr)(uint)exitCode);
  1758. }
  1759. }
  1760. catch (Exception e) {
  1761. // Don't set exitCode here; the only exception we should see is
  1762. // ProcessStopException, and Stop sets exitCode in this case.
  1763. Tracing.Log(Tracing.Fatal, "Main thread failed with exception {0}.{1}",
  1764. e.GetType().Namespace, e.GetType().Name);
  1765. Tracing.Log(Tracing.Trace, "Exception message was {0}",
  1766. e.ToString());
  1767. DebugStub.WriteLine("Process.cs: Caught exception {0}.", __arglist(e.ToString()));
  1768. }
  1769. }
  1770. // Start the execution of the new thread within the PE Image.
  1771. private void PeStartThread()
  1772. {
  1773. UIntPtr entryPoint = image.GetEntryPoint(loadedImage);
  1774. int threadIndex = Thread.CurrentThread.processThreadIndex;
  1775. int threadExit = 0;
  1776. Tracing.Log(Tracing.Debug,
  1777. "PeStartThread(entry={0:x8}, threadIndex={1}",
  1778. entryPoint, (uint)threadIndex);
  1779. #if VERBOSE
  1780. DebugStub.WriteLine("calling CallEntryPoint for thread");
  1781. DebugStub.WriteLine(" entry:{0:x8}, threadIndex={1}",
  1782. __arglist((uint)entryPoint, threadIndex));
  1783. #endif
  1784. try {
  1785. Tracing.Log(Tracing.Audit, "Calling thread entryPoint={0:x}", entryPoint);
  1786. Kernel.Waypoint(532);
  1787. #if THREAD_TIME_ACCOUNTING
  1788. Processor.GetCurrentThread().context.lastExecutionTimeUpdate =
  1789. Processor.CycleCount;
  1790. #endif
  1791. threadExit = PEImage.CallEntryPoint(entryPoint, threadIndex,
  1792. !RunsAtKernelPrivilege);
  1793. Kernel.Waypoint(533);
  1794. unchecked {
  1795. Tracing.Log(Tracing.Audit, "Thread exited with (exit={0})",
  1796. (UIntPtr)(uint)threadExit);
  1797. }
  1798. }
  1799. catch (Exception e) {
  1800. Tracing.Log(Tracing.Fatal, "Process thread failed with exception {0}.{1}",
  1801. e.GetType().Namespace, e.GetType().Name);
  1802. Tracing.Log(Tracing.Trace, "Exception message was {0}",
  1803. e.ToString());
  1804. DebugStub.WriteLine("Caught exception {0}.", __arglist(e.ToString()));
  1805. }
  1806. }
  1807. public ProcessState State {
  1808. get { return this.state; }
  1809. }
  1810. #region HandleTable
  1811. public unsafe UIntPtr AllocateHandle()
  1812. {
  1813. return handles.AllocateHandle();
  1814. }
  1815. public unsafe UIntPtr AllocateHandle(object obj)
  1816. {
  1817. DebugStub.Assert(obj != null, "Can't allocate handle for null object.");
  1818. UIntPtr handle = handles.AllocateHandle();
  1819. HandleTable.SetHandle(handle, obj);
  1820. return handle;
  1821. }
  1822. public void ReleaseHandle(UIntPtr id)
  1823. {
  1824. unchecked {
  1825. Tracing.Log(Tracing.Debug, "Process[{0:x3}].ReleaseHandle(id={1:x})",
  1826. (UIntPtr)(uint)processIndex, id);
  1827. }
  1828. handles.FreeHandle(id);
  1829. }
  1830. #endregion
  1831. }
  1832. }