1 using System;
   2 using System.Collections;
   3 using cmsx.machine;
   4 
   5 namespace cmsx.kernel
   6 {
   7     public const int numProcessSlots = 1024;
   8     public const int noPID = -1;
   9     public const int idlePID = 0;
  10     public const ulong noEvent = 0u;
  11     public const ulong childExitEvent = 1u;
  12     public const ulong consoleInputEvent = 2u;
  13     public const ulong wakeupEvent = 3u;
  14     public const ulong blockUnlockedEvent = 4u;
  15     public const ulong anyBlockFreeEvent = 5u;
  16     public const ulong blockIOEvent = 6u;
  17     public const ulong inodeUnlockedEvent = 7u;
  18     public const ulong pipeNotFullEvent = 8u;
  19     public const ulong pipeNotEmptyEvent = 9u;
  20 
  21     public nothrow string EventStr(ulong eventulong eventData1ulong eventData2)
  22     {
  23         string eventStr;
  24         switch (event)
  25         {
  26             case childExitEvent: eventStr.Append("child.exit.").Append(ToHexString(eventData1)); break;
  27             case consoleInputEvent: eventStr.Append("console.input.").Append(ToHexString(eventData1)).Append('.').Append(ToString(eventData2)); break;
  28             case wakeupEvent: eventStr.Append("proc.wakeup.").Append(ToString(eventData1)); break;
  29             case blockUnlockedEvent: eventStr.Append("block.unlocked.").Append(cast<Block*>(cast<void*>(eventData1))->ToString()); break;
  30             case anyBlockFreeEvent: eventStr.Append("anyblock.free"); break;
  31             case blockIOEvent: eventStr.Append("blockio.ready.").Append(cast<Block*>(cast<void*>(eventData1))->ToString()); break;
  32             case inodeUnlockedEvent: eventStr.Append("inode.unlocked.").Append(cast<INode*>(cast<void*>(eventData1))->ToString()); break;
  33             case pipeNotFullEvent: eventStr.Append("pipe.not.full"); break;
  34             case pipeNotEmptyEvent: eventStr.Append("pipe.not.empty"); break;
  35         }
  36         return eventStr;
  37     }
  38 
  39     public nothrow string ProcessName(Process* process)
  40     {
  41         string s;
  42         if (process != null)
  43         {
  44             s.Append(process->name).Append(".pid=").Append(ToString(process->pid));
  45         }
  46         else
  47         {
  48             s.Append("kernel");
  49         }
  50         return s;
  51     }
  52 
  53     public class Process
  54     {
  55         public enum State : byte
  56         {
  57             free = 0ucreated = 1ureadyToRun = 2urunning = 3uasleep = 5uzombie = 6u
  58         }
  59         public enum Mode : byte
  60         {
  61             runningUserrunningKernel
  62         }
  63         public nothrow Process() : 
  64             pid(noPID)pgid(noPID)state(State.free)mode(Mode.runningUser)parent(null)firstChild(null)lastChild(null)nextSibling(null)nextFree(null)memoryTable()
  65             sp(0u)regAXAddress(0u)regBXAddress(0u)regCXAddress(0u)exitCode(0u)event(noEvent)eventData1(0u)eventData2(0u)systemCallReady(false)umask(0)unsave(false)
  66         {
  67         }
  68         public nothrow void AddChild(Process* child)
  69         {
  70             #assert(child != null);
  71             #assert(child->nextSibling == null);
  72             if (lastChild != null)
  73             {
  74                 #assert(lastChild->nextSibling == null);
  75                 lastChild->nextSibling = child;
  76             }
  77             lastChild = child;
  78             if (firstChild == null)
  79             {
  80                 firstChild = child;
  81             }
  82             child->parent = this;
  83         }
  84         public nothrow void RemoveChild(Process* prevChildProcess* child)
  85         {
  86             #assert(child != null);
  87             #assert(prevChild != child);
  88             if (prevChild != null)
  89             {
  90                 prevChild->nextSibling = child->nextSibling;
  91             }
  92             if (lastChild == child)
  93             {
  94                 lastChild = prevChild;
  95             }
  96             if (firstChild == child)
  97             {
  98                 firstChild = child->nextSibling;
  99             }
 100             child->nextSibling = null;
 101             child->parent = null;
 102         }
 103         public int pid;
 104         public int pgid;
 105         public int sid;
 106         public int uid;
 107         public int gid;
 108         public string name;
 109         public ulong entryPoint;
 110         public State state;
 111         public Mode mode;
 112         public Process* parent;
 113         public Process* firstChild;
 114         public Process* lastChild;
 115         public Process* nextSibling;
 116         public Process* nextFree;
 117         public MemoryTable memoryTable;
 118         public ProcessFileTable fileTable;
 119         public INodeKey rootDirINodeKey;
 120         public INodeKey workingDirINodeKey;
 121         public INodeKey executableINodeKey;
 122         public int umask;
 123         public ulong sp;
 124         public ulong regAXAddress;
 125         public ulong regBXAddress;
 126         public ulong regCXAddress;
 127         public ushort exitCode;
 128         public ulong event;
 129         public ulong eventData1;
 130         public ulong eventData2;
 131         public ulong poolStart;
 132         public ulong poolEnd;
 133         public ulong functionTableAddress;
 134         public ulong functionTableLength;
 135         public ulong currentExceptionAddress;
 136         public ulong currentExceptionClassId;
 137         public ulong handlerAddress;
 138         public ulong currentExceptionFrameSize;
 139         public SystemCall systemCall;
 140         public SystemError lastError;
 141         public bool systemCallReady;
 142         public void* fiber;
 143         public bool unsave;
 144         public Duration kernelTime;
 145         public Duration userTime;
 146         public Duration childKernelTime;
 147         public Duration childUserTime;
 148         public TimePoint kernelStart;
 149         public TimePoint userStart;
 150     }
 151 
 152     public class ProcessTable
 153     {
 154         static ProcessTable() : instance(new ProcessTable())
 155         {
 156         }
 157         public static nothrow ProcessTable& Instance()
 158         {
 159             return *instance;
 160         }
 161         private ProcessTable() : machine(GetMachine())nextPID(1)free(null)init(null)running(null)readyQueue()nextFreeProcessSlot(0)
 162         {
 163         }
 164         public Process* CreateProcess(const string& nameulong entryPointulong textSegmentBaseAddressulong textSegmentSizeulong dataSegmentSizeulong poolSegmentSize
 165             ulong minStackSegmentSizeulong maxStackSegmentSizeulong stackSegmentIncrementint sid)
 166         {
 167             Process* process = null;
 168             if (free != null)
 169             {
 170                 process = free;
 171                 free = free->nextFree;
 172             }
 173             else if (nextFreeProcessSlot < numProcessSlots)
 174             {
 175                 process = &processSlots[nextFreeProcessSlot++];
 176             }
 177             else
 178             {
 179                 throw SystemError(ERLIMITEXCEEDED"maximum number of simultaneous processes (" + ToString(numProcessSlots) + " exceeeded");
 180             }
 181             if (nextPID == idlePID)
 182             {
 183                 ++nextPID;
 184             }
 185             process->pid = nextPID++;
 186             process->pgid = process->pid;
 187             process->sid = sid;
 188             process->uid = 0;
 189             process->gid = 0;
 190             process->name = name;
 191             process->entryPoint = entryPoint;
 192             process->state = Process.State.created;
 193             process->parent = null;
 194             process->firstChild = null;
 195             process->lastChild = null;
 196             process->nextSibling = null;
 197             process->nextFree = null;
 198             InitializeProcessMemory(machineprocesstextSegmentBaseAddresstextSegmentSizedataSegmentSizepoolSegmentSizeminStackSegmentSizemaxStackSegmentSizestackSegmentIncrement);
 199             InitializeFileTable(machineprocess->fileTable);
 200             FileSystem* fs = GetMountTable().GetFileSystem(0);
 201             process->rootDirINodeKey = fs->GetRootDirINodeKey();
 202             process->workingDirINodeKey = process->rootDirINodeKey;
 203             process->umask = 0;
 204             AddProcessToProcessMap(process);
 205             process->kernelTime = Duration(0);
 206             process->userTime = Duration(0);
 207             process->childKernelTime = Duration(0);
 208             process->childUserTime = Duration(0);
 209             process->kernelStart = TimePoint(0);
 210             process->userStart = TimePoint(0);
 211             return process;
 212         }
 213         public nothrow Process* CloneProcess(Process* parent)
 214         {
 215             Process* child = null;
 216             if (free != null)
 217             {
 218                 child = free;
 219                 free = free->nextFree;
 220             }
 221             else if (nextFreeProcessSlot < numProcessSlots)
 222             {
 223                 child = &processSlots[nextFreeProcessSlot++];
 224             }
 225             else
 226             {
 227                 return null;
 228             }
 229             if (nextPID == idlePID)
 230             {
 231                 ++nextPID;
 232             }
 233             child->pid = nextPID++;
 234             child->pgid = parent->pgid;
 235             child->sid = parent->sid;
 236             child->uid = parent->uid;
 237             child->gid = parent->gid;
 238             child->name = parent->name + ".child";
 239             child->state = Process.State.created;
 240             child->mode = Process.Mode.runningUser;
 241             child->parent = null;
 242             child->firstChild = null;
 243             child->lastChild = null;
 244             child->nextSibling = null;
 245             child->nextFree = null;
 246             CloneProcessMemory(machinechildparent);
 247             parent->fileTable.ShareFilesTo(child->fileTable);
 248             child->rootDirINodeKey = parent->rootDirINodeKey;
 249             child->workingDirINodeKey = parent->workingDirINodeKey;
 250             child->executableINodeKey = parent->executableINodeKey;
 251             child->umask = parent->umask;
 252             child->poolStart = parent->poolStart;
 253             child->poolEnd = parent->poolEnd;
 254             child->functionTableAddress = parent->functionTableAddress;
 255             child->functionTableLength = parent->functionTableLength;
 256             AddProcessToProcessMap(child);
 257             parent->AddChild(child);
 258             child->kernelTime = Duration(0);
 259             child->userTime = Duration(0);
 260             child->childKernelTime = Duration(0);
 261             child->childUserTime = Duration(0);
 262             child->kernelStart = TimePoint(0);
 263             child->userStart = TimePoint(0);
 264             return child;
 265         }
 266         public nothrow void FreeProcess(Process* process)
 267         {
 268             RemoveProcessFromExecutableINodeProcessMap(process);
 269             processMap.Remove(process->pid);
 270             *process = Process();
 271             process->nextFree = free;
 272             free = process;
 273         }
 274         public Process* GetProcess(int pid) const
 275         {
 276             HashMap<intProcess*>.ConstIterator it = processMap.CFind(pid);
 277             if (it != processMap.CEnd())
 278             {
 279                 return it->second;
 280             }
 281             else
 282             {
 283                 return null;
 284             }
 285         }
 286         public inline nothrow Process* GetInit() const
 287         {
 288             return init;
 289         }
 290         public inline nothrow void SetInit(Process* init_)
 291         {
 292             init = init_;
 293         }
 294         public inline nothrow Process* GetRunning() const
 295         {
 296             return running;
 297         }
 298         public inline nothrow void SetRunning(Process* running_)
 299         {
 300             running = running_;
 301         }
 302         public inline nothrow Process* GetIdle() const
 303         {
 304             return &idleProcess;
 305         }
 306         public nothrow void AddProcessToProcessMap(Process* process)
 307         {
 308             processMap[process->pid] = process;
 309         }
 310         public nothrow void AddProcessToExecutableINodeProcessMap(Process* process)
 311         {
 312             executableINodeProcessMap[process->executableINodeKey] = process;
 313         }
 314         public nothrow Process* GetProcessFromExecutableINodeProcessMap(const INodeKey& executableINodeKey) const
 315         {
 316             HashMap<INodeKeyProcess*INodeKeyHash>.ConstIterator it = executableINodeProcessMap.CFind(executableINodeKey);
 317             if (it != executableINodeProcessMap.CEnd())
 318             {
 319                 return it->second;
 320             }
 321             else
 322             {
 323                 return null;
 324             }
 325         }
 326         public nothrow void RemoveProcessFromExecutableINodeProcessMap(Process* process)
 327         {
 328             executableINodeProcessMap.Remove(process->executableINodeKey);
 329         }
 330         public inline nothrow void PutToReadyQueue(Process* process)
 331         {
 332             readyQueue.Put(process);
 333         }
 334         public inline nothrow bool ReadyQueueEmpty() const
 335         {
 336             return readyQueue.IsEmpty();
 337         }
 338         public inline nothrow Process* GetNextReadyProcess()
 339         {
 340             return readyQueue.Get();
 341         }
 342         private static UniquePtr<ProcessTable> instance;
 343         private Machine& machine;
 344         private Process[numProcessSlots] processSlots;
 345         private Process idleProcess;
 346         private int nextPID;
 347         private Process* free;
 348         private int nextFreeProcessSlot;
 349         private HashMap<intProcess*> processMap;
 350         private Process* init;
 351         private Process* running;
 352         private Queue<Process*> readyQueue;
 353         private HashMap<INodeKeyProcess*INodeKeyHash> executableINodeProcessMap;
 354     }
 355 
 356     public nothrow ProcessTable& GetProcessTable()
 357     {
 358         return ProcessTable.Instance();
 359     }
 360 
 361     public nothrow Process* CreateProcess(ProcessTable& processTableconst string& nameulong entryPoint
 362         ulong textSegmentBaseAddressulong textSegmentSizeulong dataSegmentSizeulong poolSegmentSizeulong minStackSegmentSizeulong maxStackSegmentSizeulong stackSegmentIncrementint sid)
 363     {
 364         return processTable.CreateProcess(nameentryPointtextSegmentBaseAddresstextSegmentSizedataSegmentSizepoolSegmentSizeminStackSegmentSizemaxStackSegmentSizestackSegmentIncrementsid);
 365     }
 366 
 367     public nothrow Process* CloneProcess(ProcessTable& processTableProcess* parent)
 368     {
 369         return processTable.CloneProcess(parent);
 370     }
 371 
 372     public nothrow void FreeProcess(ProcessTable& processTableProcess* process)
 373     {
 374         processTable.FreeProcess(process);
 375     }
 376 
 377     public nothrow Process* GetProcess(ProcessTable& processTableint pid)
 378     {
 379         return processTable.GetProcess(pid);
 380     }
 381 
 382     public nothrow Process* GetRunningProcess(ProcessTable& processTable)
 383     {
 384         return processTable.GetRunning();
 385     }
 386 
 387     public nothrow void SetProcessReadyToRun(ProcessTable& processTableProcess* process)
 388     {
 389         if (Log())
 390         {
 391             LogMessage("proc.setReady"ProcessName(process));
 392         }
 393         process->state = Process.State.readyToRun;
 394         processTable.PutToReadyQueue(process);
 395     }
 396 
 397     public inline nothrow ushort MakeProcessExitCode(byte signalNumberbyte userExitCode)
 398     {
 399         return (cast<ushort>(signalNumber) << 8u) | cast<ushort>(userExitCode);
 400     }
 401 
 402     public inline nothrow void UnpackProcessExitCode(ushort exitCodebyte& signalNumberbyte& userExitCode)
 403     {
 404         signalNumber = cast<byte>(exitCode >> 8u);
 405         userExitCode = cast<byte>(exitCode);
 406     }
 407 
 408     public nothrow void SleepProcess(Process* processulong eventulong eventData1ulong eventData2)
 409     {
 410         if (Log())
 411         {
 412             LogMessage("proc.sleep"ProcessName(process) + ":" + EventStr(eventeventData1eventData2));
 413         }
 414         if (process != null)
 415         {
 416             #assert(process->state == Process.State.running);
 417             process->state = Process.State.asleep;
 418             process->event = event;
 419             process->eventData1 = eventData1;
 420             process->eventData2 = eventData2;
 421             if (event != wakeupEvent)
 422             {
 423                 process->kernelTime = process->kernelTime + Now() - process->kernelStart;
 424                 OsSwitchToFiber(mainFiber);
 425                 process->kernelStart = Now();
 426             }
 427         }
 428         else
 429         {
 430             Kernel& kernel = GetKernel();
 431             kernel.SetWaiting();
 432             kernel.WaitKernelEvent();
 433             kernel.ResetWaiting();
 434         }
 435     }
 436 
 437     public nothrow void WakeUpProcess(ProcessTable& processTableProcess* process)
 438     {
 439         if (Log())
 440         {
 441             LogMessage("proc.wakeup"ProcessName(process));
 442         }
 443         if (process != null)
 444         {
 445             #assert(process->state == Process.State.asleep);
 446             process->event = 0u;
 447             process->eventData1 = 0u;
 448             process->eventData2 = 0u;
 449             SetProcessReadyToRun(processTableprocess);
 450         }
 451         else
 452         {
 453             Kernel& kernel = GetKernel();
 454             kernel.SetKernelEvent();
 455         }
 456     }
 457 
 458     public void ExitProcess(Machine& machineProcessTable& processTableProcess* processushort exitCode)
 459     {
 460         if (Log())
 461         {
 462             LogMessage("proc.exit"ProcessName(process) + ".exitCode=" + ToString(exitCode));
 463         }
 464         #assert(process->pid != idlePID);
 465         process->fileTable.ReleaseFiles();
 466         FreeProcessMemory(machine.GetMemory()process);
 467         process->exitCode = exitCode;
 468         process->state = Process.State.zombie;
 469         process->kernelTime = process->kernelTime + Now() - process->kernelStart;
 470         Process* parent = process->parent;
 471         Process* init = processTable.GetInit();
 472         if (process != init)
 473         {
 474             Process* child = process->firstChild;
 475             while (child != null)
 476             {
 477                 Process* next = child->nextSibling;
 478                 child->nextSibling = null;
 479                 init->AddChild(child);
 480                 child = next;
 481             }
 482             process->firstChild = null;
 483             process->lastChild = null;
 484         }
 485         if (parent != null)
 486         {
 487             if (parent->state == Process.State.asleep && parent->event == childExitEvent)
 488             {
 489                 WakeUpProcess(processTableparent);
 490             }
 491         }
 492         Schedule(machineprocessTable);
 493     }
 494 
 495     public int WaitProcess(Machine& machineProcessTable& processTableProcess* processulong exitCodeAddress)
 496     {
 497         if (Log())
 498         {
 499             LogMessage("proc.wait"ProcessName(process));
 500         }
 501         while (true)
 502         {
 503             Process* child = process->firstChild;
 504             if (child == null)
 505             {
 506                 process->lastError = SystemError(EFAIL"process has no children");
 507                 return -1;
 508             }
 509             else
 510             {
 511                 Process* prevChild = null;
 512                 while (child != null)
 513                 {
 514                     if (child->state == Process.State.zombie)
 515                     {
 516                         if (exitCodeAddress != 0u)
 517                         {
 518                             WriteProcessMemory(machineprocessexitCodeAddresschild->exitCode2uProtection.write);
 519                         }
 520                         int childPID = child->pid;
 521                         process->childKernelTime = process->childKernelTime + child->kernelTime;
 522                         process->childUserTime = process->childUserTime + child->userTime;
 523                         process->RemoveChild(prevChildchild);
 524                         FreeProcess(processTablechild);
 525                         if (Log())
 526                         {
 527                             LogMessage("proc.wait""return." + ProcessName(process) + ".childPID=" + ToString(childPID));
 528                         }
 529                         return childPID;
 530                     }
 531                     prevChild = child;
 532                     child = child->nextSibling;
 533                 }
 534                 SleepProcess(processchildExitEventexitCodeAddress0u);
 535             }
 536         }
 537     }
 538 
 539     public int ForkProcess(Machine& machineProcessTable& processTableProcess* parent)
 540     {
 541         Process* child = CloneProcess(processTableparent);
 542         SetProcessReadyToRun(processTablechild);
 543         WriteProcessMemory(machinechildchild->regAXAddress0u8uProtection.write);
 544         return child->pid;
 545     }
 546 
 547     public void SendSignalProcess(Machine& machineProcessTable& processTableProcess* processint pidint sig)
 548     {
 549         Process* target = processTable.GetProcess(pid);
 550         ExitProcess(machineprocessTabletarget0x100u);
 551     }
 552 
 553     public void SetUIDProcess(Process* processint uid)
 554     {
 555         if (process->uid == 0)
 556         {
 557             process->uid = uid;
 558         }
 559         else
 560         {
 561             throw SystemError(EPERM"unauthorized");
 562         }
 563         // set effective uid also
 564     }
 565 
 566     public void SetGIDProcess(Process* processint gid)
 567     {
 568         if (process->gid == 0)
 569         {
 570             process->gid = gid;
 571         }
 572         else
 573         {
 574             throw SystemError(EPERM"unauthorized");
 575         }
 576         // set effective gid also
 577     }
 578 
 579     public int SetPoolEndProcess(Machine& machineProcess* processulong poolEndAddress)
 580     {
 581         if (poolEndAddress < poolSegmentBaseAddress || poolEndAddress >= stackSegmentBaseAddress)
 582         {
 583             throw SystemError(EINVAL"set_pool_end: invalid virtual address " + ToHexString(poolEndAddress));
 584         }
 585         if (poolEndAddress < process->poolStart)
 586         {
 587             throw SystemError(EINVAL"set_pool_end: invalid virtual address " + ToHexString(poolEndAddress));
 588         }
 589         if (poolEndAddress > process->poolEnd)
 590         {
 591             poolEndAddress = pageSize * ((poolEndAddress - 1u) / pageSize + 1u);
 592             try
 593             {
 594                 GrowSegment(machine.GetMemory()process->memoryTablepoolSegmentIndexpoolEndAddress - process->poolEnd);
 595                 process->poolEnd = poolEndAddress;
 596                 return 0;
 597             }
 598             catch (const SystemError& error)
 599             {
 600                 throw;
 601             }
 602             catch (const Exception& ex)
 603             {
 604                 throw SystemError(EINVAL"set_pool_end: could not grow pool segment: " + ex.Message());
 605             }
 606         }
 607         else if (poolEndAddress < process->poolEnd)
 608         {
 609             poolEndAddress = pageSize * (poolEndAddress / pageSize);
 610             try
 611             {
 612                 ShrinkSegment(machine.GetMemory()process->memoryTablepoolSegmentIndexprocess->poolEnd - poolEndAddress);
 613                 process->poolEnd = poolEndAddress;
 614                 return 0;
 615             }
 616             catch (const SystemError& error)
 617             {
 618                 throw;
 619             }
 620             catch (const Exception& ex)
 621             {
 622                 throw SystemError(EINVAL"set_pool_end: could not shrink pool segment: " + ex.Message());
 623             }
 624         }
 625         return 0;
 626     }
 627 
 628     public string GetProcessStackTrace(Machine& machineProcess* processulong fp)
 629     {
 630         List<cmsx.object.FunctionTableEntry> functionTable;
 631         ReadFunctionTableFromProcessMemory(machineprocessprocess->functionTableAddressprocess->functionTableLengthfunctionTable);
 632         List<ulong> pcs;
 633         string stackTrace = "STACK TRACE:\n";
 634         ulong pc = 0u;
 635         ReadProcessMemory(machineprocessfp - 8upc8ufalse);
 636         while (pc != 0u)
 637         {
 638             pcs.Add(pc);
 639             try
 640             {
 641                 ulong prevFP = 0u;
 642                 ReadProcessMemory(machineprocessfpprevFP8ufalse);
 643                 fp = prevFP;
 644                 ReadProcessMemory(machineprocessfp - 8upc8ufalse);
 645             }
 646             catch (const Exception& ex)
 647             {
 648                 pc = 0u;
 649             }
 650         }
 651         long n = pcs.Count();
 652         for (long i = n - 1; i >= 0; --i;)
 653         {
 654             ulong pc = pcs[i];
 655             List<cmsx.object.FunctionTableEntry>.ConstIterator first = functionTable.CBegin();
 656             List<cmsx.object.FunctionTableEntry>.ConstIterator last = functionTable.CEnd();
 657             cmsx.object.FunctionTableEntry entry(pc0u0u0u0u0u0u0u);
 658             List<cmsx.object.FunctionTableEntry>.ConstIterator it = LowerBound(firstlastentry);
 659             if (it != first && it == last)
 660             {
 661                 --it;
 662             }
 663             if (it != first && it != last && entry.start < it->start)
 664             {
 665                 --it;
 666             }
 667             if (it != last && entry.start >= it->start && entry.start < it->start + it->length)
 668             {
 669                 ulong fullNameAddress = it->fullNameAddress;
 670                 string fullName;
 671                 ReadStringFromProcessMemory(machineprocessdataSegmentBaseAddress + fullNameAddressfullName);
 672                 ulong mangledNameAddress = it->mangledNameAddress;
 673                 string mangledName;
 674                 ReadStringFromProcessMemory(machineprocessdataSegmentBaseAddress + mangledNameAddressmangledName);
 675                 ulong sourceFileNameAddress = it->sourceFileNameAddress;
 676                 string sourceFileName;
 677                 if (sourceFileNameAddress != 0u)
 678                 {
 679                     ReadStringFromProcessMemory(machineprocessdataSegmentBaseAddress + sourceFileNameAddresssourceFileName);
 680                 }
 681                 string lineNumberStr;
 682                 ulong lineNumberTableStartAddress = it->lineNumberTableStartAddress;
 683                 ulong lineNumberTableEndAddress = it->lineNumberTableEndAddress;
 684                 List<cmsx.object.LineNumberTableEntry> lineNumberTable;
 685                 ReadLineNumberTableFromProcessMemory(machineprocessdataSegmentBaseAddress + lineNumberTableStartAddressdataSegmentBaseAddress + lineNumberTableEndAddresslineNumberTable);
 686                 List<cmsx.object.LineNumberTableEntry>.ConstIterator lnFirst = lineNumberTable.CBegin();
 687                 List<cmsx.object.LineNumberTableEntry>.ConstIterator lnLast = lineNumberTable.CEnd();
 688                 cmsx.object.LineNumberTableEntry lnEntry(cast<uint>(pc - it->start)0u);
 689                 List<cmsx.object.LineNumberTableEntry>.ConstIterator lnIt = LowerBound(lnFirstlnLastlnEntry);
 690                 if (lnIt != lnFirst && lnIt == lnLast)
 691                 {
 692                     --lnIt;
 693                 }
 694                 if (lnIt != lnFirst && lnIt != lnLast && lnEntry.offset > lnIt->offset)
 695                 {
 696                     --lnIt;
 697                 }
 698                 if (lnIt != lnLast)
 699                 {
 700                     uint lineNumber = lnIt->lineNumber;
 701                     lineNumberStr.Append(':').Append(ToString(lineNumber));
 702                 }
 703                 string sourceFileNameStr;
 704                 if (!sourceFileName.IsEmpty())
 705                 {
 706                     sourceFileNameStr.Append(" : ").Append(sourceFileName);
 707                 }
 708                 stackTrace.Append(ToString(i)).Append(": ").Append(fullName).Append(" : ").Append(mangledName).Append(sourceFileNameStr).Append(lineNumberStr).Append('\n');
 709             }
 710         }
 711         stackTrace.Append('\n');
 712         return stackTrace;
 713     }
 714 
 715     public void GetProcessStackTrace(Machine& machineProcess* processulong fpulong bufferlong count)
 716     {
 717         if (buffer < poolSegmentBaseAddress || buffer >= stackSegmentBaseAddress)
 718         {
 719             throw SystemError(EINVAL"invalid buffer virtual address " + ToHexString(buffer));
 720         }
 721         if (count <= 0)
 722         {
 723             throw SystemError(EINVAL"invalid count " + ToString(count));
 724         }
 725         string stackTrace = GetProcessStackTrace(machineprocessfp);
 726         if (count < stackTrace.Length())
 727         {
 728             stackTrace = stackTrace.Substring(stackTrace.Length() - count);
 729         }
 730         if (count > stackTrace.Length())
 731         {
 732             count = stackTrace.Length();
 733         }
 734         long len = Max(cast<long>(0)count - 1);
 735         if (len > 0)
 736         {
 737             WriteProcessMemory(machineprocessbuffercast<byte*>(cast<void*>(stackTrace.Chars()))cast<ulong>(len)Protection.write);
 738         }
 739         WriteProcessMemory(machineprocessbuffer + cast<ulong>(len)0u1uProtection.write);
 740     }
 741 
 742     public void GetProcessSystemError(Machine& machineProcess* processulong errorCodeAddressulong bufferAddresslong count)
 743     {
 744         if (errorCodeAddress != 0u && errorCodeAddress < dataSegmentBaseAddress)
 745         {
 746             throw SystemError(EINVAL"invalid error code virtual address " + ToHexString(errorCodeAddress));
 747         }
 748         if (bufferAddress < poolSegmentBaseAddress || bufferAddress >= stackSegmentBaseAddress)
 749         {
 750             throw SystemError(EINVAL"invalid buffer virtual address " + ToHexString(bufferAddress));
 751         }
 752         if (count <= 0)
 753         {
 754             throw SystemError(EINVAL"invalid count " + ToString(count));
 755         }
 756         if (errorCodeAddress != 0u)
 757         {
 758             int errorCode = process->lastError.errorCode;
 759             WriteProcessMemory(machineprocesserrorCodeAddresscast<ulong>(errorCode)4uProtection.write);
 760         }
 761         string errorMessage = process->lastError.Message();
 762         long len = Max(cast<long>(0)count - 1);
 763         if (len > 0)
 764         {
 765             WriteProcessMemory(machineprocessbufferAddresscast<byte*>(cast<void*>(errorMessage.Chars()))cast<ulong>(len)Protection.write);
 766         }
 767         WriteProcessMemory(machineprocessbufferAddress + cast<ulong>(len)0u1uProtection.write);
 768     }
 769 
 770     public nothrow void SaveContext(Machine& machineProcess* process)
 771     {
 772         ulong sp = process->memoryTable.segmentDescriptors[stackSegmentIndex]->baseAddress + process->memoryTable.segmentDescriptors[stackSegmentIndex]->startAddress;
 773         Registers& regs = machine.GetRegisters();
 774         ulong prevAX = regs.Get(regAX);
 775         ulong prevBX = regs.Get(regBX);
 776         ulong prevCX = regs.Get(regCX);
 777         ulong prevDX = regs.Get(regDX);
 778         ulong prevEX = regs.Get(regEX);
 779         ulong prevFP = regs.Get(regFP);
 780         ulong prevIX = regs.Get(regIX);
 781         ulong prevPC = regs.GetPC();
 782         ulong prevRL = regs.GetSpecial(Registers.rL);
 783         ulong prevRG = regs.GetSpecial(Registers.rG);
 784         ulong pc = process->entryPoint;
 785         regs.SetPC(pc);
 786         regs.Set(regAX0u);
 787         regs.Set(regBX0u);
 788         regs.Set(regCX0u);
 789         regs.Set(regDX0u);
 790         regs.Set(regEX0u);
 791         regs.Set(regFP0u);
 792         regs.Set(regIX0u);
 793         regs.SetSpecial(Registers.rL0u);
 794         regs.SetSpecial(Registers.rGfirstGlobalReg);
 795         process->sp = machine.GetProcessor().SaveContext(process->memoryTable.virtualTranslationRegisterValuesp&process->regAXAddress&process->regBXAddress&process->regCXAddress);
 796         regs.Set(regAXprevAX);
 797         regs.Set(regBXprevBX);
 798         regs.Set(regCXprevCX);
 799         regs.Set(regDXprevDX);
 800         regs.Set(regEXprevEX);
 801         regs.Set(regFPprevFP);
 802         regs.Set(regIXprevIX);
 803         regs.SetPC(prevPC);
 804         regs.SetSpecial(Registers.rLprevRL);
 805         regs.SetSpecial(Registers.rGprevRG);
 806     }
 807 
 808     public nothrow void InitializeProcessMemory(Machine& machineProcess* process
 809         ulong textSegmentStartAddressulong textSegmentSizeulong dataSegmentSizeulong poolSegmentSizeulong minStackSegmentSizeulong maxStackSegmentSizeulong stackSegmentIncrement)
 810     {
 811         InitializeMemoryTable(machineprocess->memoryTabletextSegmentStartAddresstextSegmentSizedataSegmentSizepoolSegmentSizeminStackSegmentSizemaxStackSegmentSizestackSegmentIncrement);
 812         AllocateMemory(machine.GetMemory()process->memoryTablefalse);
 813         SaveContext(machineprocess);
 814     }
 815 
 816     public void CloneProcessMemory(Machine& machineProcess* childProcess* parent)
 817     {
 818         InitializeMemoryTableForCloning(machinechild->memoryTable);
 819         CloneMemory(machine.GetMemory()child->memoryTableparent->memoryTable);
 820         Registers& regs = machine.GetRegisters();
 821         child->sp = machine.GetProcessor().SaveContext(child->memoryTable.virtualTranslationRegisterValueregs.Get(regSP)&child->regAXAddress&child->regBXAddress&child->regCXAddress);
 822     }
 823 
 824     public nothrow void FreeProcessMemory(Memory& memProcess* process)
 825     {
 826         FreeMemory(memprocess->memoryTable);
 827     }
 828 
 829     public void ReadProcessMemory(Machine& machineProcess* processulong addressulong& valuebyte size)
 830     {
 831         ReadProcessMemory(machineprocessaddressvaluesizetrue);
 832     }
 833 
 834     public void ReadProcessMemory(Machine& machineProcess* processulong addressulong& valuebyte sizebool pageFault)
 835     {
 836         Memory& mem = machine.GetMemory();
 837         Registers& regs = machine.GetRegisters();
 838         ulong prevRV = regs.GetSpecial(Registers.rV);
 839         MemoryTable& memoryTable = process->memoryTable;
 840         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 841         bool error = false;
 842         switch (size)
 843         {
 844             case 1u: value = cast<ulong>(mem.ReadByte(addressProtection.readpageFault)); break;
 845             case 2u: value = cast<ulong>(mem.ReadUShort(addressProtection.readpageFault)); break;
 846             case 4u: value = cast<ulong>(mem.ReadUInt(addressProtection.readpageFault)); break;
 847             case 8u: value = cast<ulong>(mem.ReadULong(addressProtection.readpageFault)); break;
 848             default: regs.SetSpecial(Registers.rVprevRV); error = true; break;
 849         }
 850         regs.SetSpecial(Registers.rVprevRV);
 851         if (error)
 852         {
 853             throw Exception("internal error: could not read process memory: invalid size " + ToString(size));
 854         }
 855     }
 856 
 857     public void ReadProcessMemory(Machine& machineProcess* processulong addressbyte* bufferulong size)
 858     {
 859         ReadProcessMemory(machineprocessaddressbuffersizetrue);
 860     }
 861 
 862     public void ReadProcessMemory(Machine& machineProcess* processulong addressbyte* bufferulong sizebool pageFault)
 863     {
 864         Memory& mem = machine.GetMemory();
 865         Registers& regs = machine.GetRegisters();
 866         ulong prevRV = regs.GetSpecial(Registers.rV);
 867         MemoryTable& memoryTable = process->memoryTable;
 868         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 869         for (ulong i = 0u; i < size; ++i;)
 870         {
 871             *buffer = mem.ReadByte(addressProtection.readpageFault);
 872             ++buffer;
 873             ++address;
 874         }
 875         regs.SetSpecial(Registers.rVprevRV);
 876     }
 877 
 878     public void ReadStringFromProcessMemory(Machine& machineProcess* processulong addressstring& s)
 879     {
 880         Memory& mem = machine.GetMemory();
 881         Registers& regs = machine.GetRegisters();
 882         ulong prevRV = regs.GetSpecial(Registers.rV);
 883         MemoryTable& memoryTable = process->memoryTable;
 884         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 885         byte x = mem.ReadByte(addressProtection.read);
 886         while (x != 0u)
 887         {
 888             s.Append(cast<char>(x));
 889             ++address;
 890             x = mem.ReadByte(addressProtection.read);
 891         }
 892         regs.SetSpecial(Registers.rVprevRV);
 893     }
 894 
 895     public void ReadFunctionTableFromProcessMemory(Machine& machineProcess* processulong functionTableAddressulong functionTableLengthList<cmsx.object.FunctionTableEntry>& functionTable)
 896     {
 897         Memory& mem = machine.GetMemory();
 898         Registers& regs = machine.GetRegisters();
 899         ulong prevRV = regs.GetSpecial(Registers.rV);
 900         MemoryTable& memoryTable = process->memoryTable;
 901         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 902         ulong functionTableEndAddress = functionTableAddress + functionTableLength;
 903         for (ulong address = functionTableAddress; address < functionTableEndAddress; address = address + cast<ulong>(sizeof(cmsx.object.FunctionTableEntry));)
 904         {
 905             cmsx.object.FunctionTableEntry entry;
 906             entry.start = mem.ReadULong(addressProtection.read);
 907             entry.length = mem.ReadULong(address + 8uProtection.read);
 908             entry.mangledNameAddress = mem.ReadULong(address + 16uProtection.read);
 909             entry.fullNameAddress = mem.ReadULong(address + 24uProtection.read);
 910             entry.sourceFileNameAddress = mem.ReadULong(address + 32uProtection.read);
 911             entry.lineNumberTableStartAddress = mem.ReadULong(address + 40uProtection.read);
 912             entry.lineNumberTableEndAddress = mem.ReadULong(address + 48uProtection.read);
 913             entry.exceptionTableAddress = mem.ReadULong(address + 56uProtection.read);
 914             functionTable.Add(entry);
 915         }
 916         regs.SetSpecial(Registers.rVprevRV);
 917     }
 918 
 919     public void ReadLineNumberTableFromProcessMemory(Machine& machineProcess* processulong lineNumberTableStartAddressulong lineNumberTableEndAddress
 920         List<cmsx.object.LineNumberTableEntry>& lineNumberTable)
 921     {
 922         Memory& mem = machine.GetMemory();
 923         Registers& regs = machine.GetRegisters();
 924         ulong prevRV = regs.GetSpecial(Registers.rV);
 925         MemoryTable& memoryTable = process->memoryTable;
 926         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 927         for (ulong address = lineNumberTableStartAddress; address < lineNumberTableEndAddress; address = address + cast<ulong>(sizeof(cmsx.object.LineNumberTableEntry));)
 928         {
 929             cmsx.object.LineNumberTableEntry entry;
 930             entry.offset = mem.ReadUInt(addressProtection.read);
 931             entry.lineNumber = mem.ReadUInt(address + 4uProtection.read);
 932             lineNumberTable.Add(entry);
 933         }
 934         regs.SetSpecial(Registers.rVprevRV);
 935     }
 936 
 937     public void WriteProcessMemory(Machine& machineProcess* processulong addressulong valuebyte sizeProtection access)
 938     {
 939         if (process->state == Process.State.created || process->state == Process.State.readyToRun || process->state == Process.State.running || process->state == Process.State.asleep)
 940         {
 941             Memory& mem = machine.GetMemory();
 942             Registers& regs = machine.GetRegisters();
 943             ulong prevRV = regs.GetSpecial(Registers.rV);
 944             MemoryTable& memoryTable = process->memoryTable;
 945             regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 946             bool error = false;
 947             switch (size)
 948             {
 949                 case 1u: mem.WriteByte(addresscast<byte>(value)access); break;
 950                 case 2u: mem.WriteUShort(addresscast<ushort>(value)access); break;
 951                 case 4u: mem.WriteUInt(addresscast<uint>(value)access); break;
 952                 case 8u: mem.WriteULong(addressvalueaccess); break;
 953                 default: regs.SetSpecial(Registers.rVprevRV); error = true; break;
 954             }
 955             regs.SetSpecial(Registers.rVprevRV);
 956             if (error)
 957             {
 958                 throw Exception("internal error: kernel could not write to process memory: invalid size " + ToString(size));
 959             }
 960         }
 961         else
 962         {
 963             throw Exception("internal error: kernel could not write to process memory because process state not valid");
 964         }
 965     }
 966 
 967     public void WriteProcessMemory(Machine& machineProcess* processulong targetAddressbyte* sourceulong sizeProtection access)
 968     {
 969         if (process->state == Process.State.created || process->state == Process.State.readyToRun || process->state == Process.State.running || process->state == Process.State.asleep)
 970         {
 971             Memory& mem = machine.GetMemory();
 972             Registers& regs = machine.GetRegisters();
 973             ulong prevRV = regs.GetSpecial(Registers.rV);
 974             MemoryTable& memoryTable = process->memoryTable;
 975             regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
 976             ulong address = targetAddress;
 977             for (ulong i = 0u; i < size; ++i;)
 978             {
 979                 mem.WriteByte(address*sourceaccess);
 980                 ++address;
 981                 ++source;
 982             }
 983             regs.SetSpecial(Registers.rVprevRV);
 984         }
 985         else
 986         {
 987             throw Exception("internal error: kernel could not write to process memory because process state not valid");
 988         }
 989     }
 990 
 991     public nothrow void InitializeIdleProcess(Machine& machineProcessTable& processTableProcess* idleProcess)
 992     {
 993         idleProcess->pid = idlePID;
 994         idleProcess->pgid = idlePID;
 995         idleProcess->name = "idle";
 996         idleProcess->entryPoint = 4096u;
 997         idleProcess->state = Process.State.readyToRun;
 998         idleProcess->parent = null;
 999         idleProcess->firstChild = null;
1000         idleProcess->lastChild = null;
1001         idleProcess->nextSibling = null;
1002         idleProcess->nextFree = null;
1003         InitializeProcessMemory(machineidleProcess4096u4096u0u0u4096u4096u0u);
1004         Registers& regs = machine.GetRegisters();
1005         Memory& mem = machine.GetMemory();
1006         MemoryTable& memoryTable = idleProcess->memoryTable;
1007         ulong prevRV = regs.GetSpecial(Registers.rV);
1008         regs.SetSpecial(Registers.rVmemoryTable.virtualTranslationRegisterValue);
1009         ulong addr = memoryTable.segmentDescriptors[textSegmentIndex]->startAddress;
1010         mem.WriteByte(addrSWYMProtection.execute);
1011         ++addr;
1012         mem.WriteByte(addr0uProtection.execute);
1013         ++addr;
1014         mem.WriteByte(addr0uProtection.execute);
1015         ++addr;
1016         mem.WriteByte(addr0uProtection.execute);
1017         ++addr;
1018         mem.WriteByte(addrJMPBProtection.execute);
1019         ++addr;
1020         mem.WriteByte(addr0x00uProtection.execute);
1021         ++addr;
1022         mem.WriteByte(addr0x00uProtection.execute);
1023         ++addr;
1024         mem.WriteByte(addr0x1uProtection.execute);
1025         regs.SetSpecial(Registers.rVprevRV);
1026         processTable.AddProcessToProcessMap(idleProcess);
1027     }
1028 
1029     public Process* CreateSingleProcess(Machine& machineProcessTable& processTableconst string& nameulong entryPoint
1030         ulong textSegmentBaseAddressulong textSegmentSizeulong dataSegmentSizeulong poolSegmentSizeulong minStackSegmentSizeulong maxStackSegmentSizeulong stackSegmentIncrementint sid)
1031     {
1032         Process* idleProcess = processTable.GetIdle();
1033         InitializeIdleProcess(machineprocessTableidleProcess);
1034         Process* process = CreateProcess(processTablenameentryPointtextSegmentBaseAddresstextSegmentSizedataSegmentSizepoolSegmentSize
1035             minStackSegmentSizemaxStackSegmentSizestackSegmentIncrementsid);
1036         SetProcessReadyToRun(processTableprocess);
1037         return process;
1038     }
1039 
1040     public nothrow void Schedule(Machine& machineProcessTable& processTable)
1041     {
1042         Processor& processor = machine.GetProcessor();
1043         Process* running =  processTable.GetRunning();
1044         Process* prevRunning = running;
1045         Process* idle = processTable.GetIdle();
1046         if (processTable.ReadyQueueEmpty())
1047         {
1048             if (prevRunning == null || prevRunning->state != Process.State.running)
1049             {
1050                 running = idle;
1051             }
1052         }
1053         else
1054         {
1055             running = processTable.GetNextReadyProcess();
1056         }
1057         if (prevRunning != running)
1058         {
1059             if (prevRunning != null)
1060             {
1061                 if (prevRunning->state != Process.State.zombie && !prevRunning->unsave)
1062                 {
1063                     ulong sp = machine.GetRegisters().Get(cmsx.machine.regSP);
1064                     prevRunning->sp = processor.SaveContext(prevRunning->memoryTable.virtualTranslationRegisterValuesp
1065                         &prevRunning->regAXAddress&prevRunning->regBXAddress&prevRunning->regCXAddress);
1066                 }
1067                 if (prevRunning != idle && prevRunning->state == Process.State.running)
1068                 {
1069                     prevRunning->state = Process.State.readyToRun;
1070                     processTable.PutToReadyQueue(prevRunning);
1071                 }
1072             }
1073             running->unsave = false;
1074             running->sp = processor.UnsaveContext(running->memoryTable.virtualTranslationRegisterValuerunning->sp);
1075         }
1076         else if (running->unsave)
1077         {
1078             running->unsave = false;
1079             running->sp = processor.UnsaveContext(running->memoryTable.virtualTranslationRegisterValuerunning->sp);
1080         }
1081         processTable.SetRunning(running);
1082         running->state = Process.State.running;
1083         processor.GetRegisters().SetSpecial(Registers.rVrunning->memoryTable.virtualTranslationRegisterValue);
1084         if (Log())
1085         {
1086             if (prevRunning != running)
1087             {
1088                 LogMessage("proc.schedule"ProcessName(prevRunning) + "->" + ProcessName(running));
1089             }
1090         }
1091     }
1092 
1093     public nothrow void StartUserTime()
1094     {
1095         Kernel& kernel = Kernel.Instance();
1096         ProcessTable& processTable = kernel.GetProcessTable();
1097         Process* running =  processTable.GetRunning();
1098         running->userStart = Now();
1099     }
1100 
1101     public nothrow void StopUserTime()
1102     {
1103         Kernel& kernel = Kernel.Instance();
1104         ProcessTable& processTable = kernel.GetProcessTable();
1105         Process* running =  processTable.GetRunning();
1106         if (running->userStart != TimePoint(0))
1107         {
1108             running->userTime = running->userTime + Now() - running->userStart;
1109         }
1110     }
1111 
1112     public void Times(Machine& machineProcess* processulong kernelTimeAddressulong userTimeAddressulong childKernelTimeAddressulong childUserTimeAddress)
1113     {
1114         if (kernelTimeAddress == 0u)
1115         {
1116             throw SystemError(EINVAL"times: kernel time address is null");
1117         }
1118         if (userTimeAddress == 0u)
1119         {
1120             throw SystemError(EINVAL"times: user time address is null");
1121         }
1122         if (childKernelTimeAddress == 0u)
1123         {
1124             throw SystemError(EINVAL"times: child kernel time address is null");
1125         }
1126         if (childUserTimeAddress == 0u)
1127         {
1128             throw SystemError(EINVAL"times: child user time address is null");
1129         }
1130         WriteProcessMemory(machineprocesskernelTimeAddresscast<ulong>(process->kernelTime.Rep())8uProtection.write);
1131         WriteProcessMemory(machineprocessuserTimeAddresscast<ulong>(process->userTime.Rep())8uProtection.write);
1132         WriteProcessMemory(machineprocesschildKernelTimeAddresscast<ulong>(process->childKernelTime.Rep())8uProtection.write);
1133         WriteProcessMemory(machineprocesschildUserTimeAddresscast<ulong>(process->childUserTime.Rep())8uProtection.write);
1134     }
1135 }