Windows.Environment.Mod 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. (* Runtime environment for Windows *)
  2. (* Copyright (C) Florian Negele *)
  3. MODULE Environment;
  4. IMPORT SYSTEM, Activities, Counters, Kernel32, Processors, Queues, Trace;
  5. CONST IsNative* = FALSE;
  6. CONST Running* = 0; ShuttingDown* = 1; Rebooting* = 2;
  7. CONST DefaultConfigFile = "aos.ini";
  8. CONST UserConfigFile = "myaos.ini";
  9. VAR activity: WORD;
  10. VAR status* := 0: WORD;
  11. VAR heap: Kernel32.HANDLE;
  12. VAR sleepingQueue: Queues.Queue;
  13. VAR stdin, stdout: Kernel32.HANDLE;
  14. VAR defaultConfigFile, userConfigFile, traceName: ARRAY Kernel32.MaxPath OF CHAR;
  15. PROCEDURE {NORETURN} Abort-;
  16. BEGIN {UNCOOPERATIVE, UNCHECKED}
  17. IF Activities.GetCurrentActivity () # NIL THEN Activities.TerminateCurrentActivity END;
  18. Exit (1);
  19. END Abort;
  20. PROCEDURE Shutdown*;
  21. VAR mod: Kernel32.HANDLE;
  22. VAR SendMessage: PROCEDURE {WINAPI} (hWnd: ADDRESS; Msg: LONGINT; wParam: ADDRESS; lParam: ADDRESS): LONGINT;
  23. BEGIN {UNCOOPERATIVE, UNCHECKED}
  24. IF CAS (status, Running, ShuttingDown) # Running THEN RETURN END;
  25. Trace.StringLn ("system: shutting down...");
  26. mod := Kernel32.LoadLibrary("User32.DLL");
  27. Kernel32.GetProcAddress(mod, "PostMessageA", SYSTEM.VAL (ADDRESS,SendMessage));
  28. SendMessage (0FFFFH, 0, 0, 0);
  29. END Shutdown;
  30. PROCEDURE Reboot*;
  31. BEGIN {UNCOOPERATIVE, UNCHECKED}
  32. Shutdown;
  33. ASSERT (CAS (status, ShuttingDown, Rebooting) = ShuttingDown);
  34. END Reboot;
  35. PROCEDURE {NORETURN} Exit- (status: WORD);
  36. BEGIN {UNCOOPERATIVE, UNCHECKED}
  37. Trace.String ("system: exiting to windows");
  38. RemoveTraceFile;
  39. Kernel32.ExitProcess (status);
  40. END Exit;
  41. PROCEDURE Clock- (): LONGINT;
  42. BEGIN {UNCOOPERATIVE, UNCHECKED}
  43. RETURN Kernel32.GetTickCount ();
  44. END Clock;
  45. PROCEDURE Sleep- (milliseconds: LONGINT);
  46. VAR nextActivity: Activities.Activity;
  47. BEGIN {UNCOOPERATIVE, UNCHECKED}
  48. INC (milliseconds, Kernel32.GetTickCount ());
  49. Counters.Inc (Activities.awaiting);
  50. WHILE Kernel32.GetTickCount () - milliseconds < 0 DO
  51. IF Activities.Select (nextActivity, Activities.IdlePriority) THEN
  52. Activities.SwitchTo (nextActivity, Enqueue, NIL);
  53. Activities.FinalizeSwitch;
  54. END;
  55. END;
  56. Counters.Dec (Activities.awaiting);
  57. END Sleep;
  58. PROCEDURE Enqueue (previous {UNTRACED}: Activities.Activity; argument: ADDRESS);
  59. VAR item: Queues.Item;
  60. BEGIN {UNCOOPERATIVE, UNCHECKED}
  61. Queues.Enqueue (previous, sleepingQueue);
  62. END Enqueue;
  63. PROCEDURE {WINAPI} TimerThread (lpParameter {UNTRACED}: ANY): LONGINT;
  64. BEGIN {UNCOOPERATIVE, UNCHECKED}
  65. Kernel32.InstallExceptionHandler;
  66. Activities.CallVirtual (TickLoop, NIL, Activities.CreateVirtualProcessor ());
  67. RETURN 0;
  68. END TimerThread;
  69. PROCEDURE TickLoop (argument: ADDRESS);
  70. VAR item: Queues.Item;
  71. BEGIN
  72. WHILE status = Running DO
  73. Kernel32.Sleep (1);
  74. WHILE Queues.Dequeue (item, sleepingQueue) DO
  75. Activities.Resume (item(Activities.Activity));
  76. END;
  77. END;
  78. END TickLoop;
  79. PROCEDURE Allocate- (size: SIZE): ADDRESS;
  80. BEGIN {UNCOOPERATIVE, UNCHECKED}
  81. RETURN Kernel32.HeapAlloc(heap, Kernel32.HeapZeroMemory, size);
  82. END Allocate;
  83. PROCEDURE Deallocate- (address: ADDRESS);
  84. BEGIN {UNCOOPERATIVE, UNCHECKED}
  85. ASSERT (Kernel32.HeapFree(heap, 0, address) # 0);
  86. END Deallocate;
  87. PROCEDURE GetString- (CONST name: ARRAY OF CHAR; VAR result: ARRAY OF CHAR);
  88. CONST ConfigKey = "Configuration";
  89. BEGIN {UNCOOPERATIVE, UNCHECKED}
  90. IF Kernel32.GetPrivateProfileString (ConfigKey, name, "", result, LEN (result), userConfigFile) # 0 THEN
  91. ELSIF Kernel32.GetPrivateProfileString (ConfigKey, name, "", result, LEN (result), defaultConfigFile) # 0 THEN
  92. ELSE result[0] := 0X;
  93. END;
  94. END GetString;
  95. PROCEDURE WriteChar (char: CHAR);
  96. VAR written: LONGINT;
  97. BEGIN {UNCOOPERATIVE, UNCHECKED}
  98. ASSERT (Kernel32.WriteFile (stdout, char ,1, written, NIL) # 0);
  99. END WriteChar;
  100. PROCEDURE SetConsoleColor (color: SHORTINT);
  101. BEGIN {UNCOOPERATIVE, UNCHECKED}
  102. ASSERT (Kernel32.SetConsoleTextAttribute (stdout, color) # 0);
  103. END SetConsoleColor;
  104. PROCEDURE OutputChar (char: CHAR);
  105. VAR trace: ARRAY 2 OF CHAR;
  106. BEGIN {UNCOOPERATIVE, UNCHECKED}
  107. trace[0] := char; Kernel32.OutputString (trace);
  108. END OutputChar;
  109. PROCEDURE SetupTraceName(VAR traceName: ARRAY OF CHAR);
  110. VAR
  111. ext: ARRAY 256 OF CHAR;
  112. extPos,i,j: LONGINT;
  113. systemTime: Kernel32.SystemTime;
  114. ch: CHAR;
  115. PROCEDURE AppendDecimals(int: LONGINT; from, to: LONGINT);
  116. VAR ten: LONGINT;
  117. BEGIN {UNCOOPERATIVE, UNCHECKED}
  118. WHILE to >= from DO
  119. traceName[i] := CHR(ORD("0")+ int DIV to MOD 10); INC(i);
  120. to := to DIV 10;
  121. END;
  122. END AppendDecimals;
  123. BEGIN {UNCOOPERATIVE, UNCHECKED}
  124. Kernel32.GetLocalTime(systemTime);
  125. extPos := 0;
  126. REPEAT
  127. ch := traceName[i];
  128. IF ch = "." THEN j := 0; extPos := i END;
  129. ext[j] := ch;
  130. INC(j); INC(i);
  131. UNTIL ch = 0X;
  132. IF extPos > 0 THEN i := extPos END;
  133. ext[j] := 0X;
  134. AppendDecimals(systemTime.wYear,1,1000);
  135. AppendDecimals(systemTime.wMonth,1,10);
  136. AppendDecimals(systemTime.wDay,1,10);
  137. traceName[i] := "_"; INC(i);
  138. AppendDecimals(systemTime.wHour,1,10);
  139. AppendDecimals(systemTime.wMinute,1,10);
  140. AppendDecimals(systemTime.wSecond,1,10);
  141. traceName[i] := "_"; INC(i);
  142. AppendDecimals(systemTime.wMilliseconds,10,100);
  143. j := 0;
  144. REPEAT
  145. ch := ext[j];
  146. traceName[i] := ch;
  147. INC(i); INC(j);
  148. UNTIL ch = 0X;
  149. END SetupTraceName;
  150. PROCEDURE RemoveTraceFile;
  151. VAR res: LONGINT;
  152. BEGIN {UNCOOPERATIVE, UNCHECKED}
  153. IF traceName[0] # 0X THEN
  154. Trace.String("removing "); Trace.String(traceName); Trace.Ln;
  155. Trace.Char := OutputChar;
  156. res := Kernel32.CloseHandle(stdout);
  157. IF res = 0 THEN
  158. res := Kernel32.GetLastError();
  159. Trace.String("could not close "); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  160. END;
  161. res := Kernel32.DeleteFile(traceName);
  162. IF res = 0 THEN
  163. res := Kernel32.GetLastError();
  164. Trace.String("could not delete "); Trace.String(traceName); Trace.String("; res = "); Trace.Int(res,1); Trace.Ln;
  165. END;
  166. END;
  167. END RemoveTraceFile;
  168. PROCEDURE ToExecutablePath(CONST name: ARRAY OF CHAR; VAR fullName: ARRAY OF CHAR);
  169. VAR i, j: LONGINT;
  170. BEGIN {UNCOOPERATIVE, UNCHECKED}
  171. Kernel32.GetModuleFileName (Kernel32.hInstance, fullName, LEN (fullName));
  172. j := -1; i := 0;
  173. WHILE fullName[i] # 0X DO
  174. IF fullName[i] = '\' THEN j := i END;
  175. INC( i )
  176. END;
  177. i := 0; INC(j);
  178. WHILE name[i] # 0X DO
  179. fullName[j] := name[i]; INC(i); INC(j);
  180. END;
  181. fullName[j] := 0X;
  182. END ToExecutablePath;
  183. PROCEDURE GetInit- (n: SIZE; VAR val: LONGINT);
  184. BEGIN val := 0;
  185. END GetInit;
  186. PROCEDURE StoreActivity-;
  187. BEGIN {UNCOOPERATIVE, UNCHECKED}
  188. Kernel32.TlsSetValue(activity, SYSTEM.VAL(ADDRESS, SYSTEM.GetActivity ()));
  189. END StoreActivity;
  190. PROCEDURE RestoreActivity-;
  191. BEGIN {UNCOOPERATIVE, UNCHECKED}
  192. SYSTEM.SetActivity(SYSTEM.VAL(Activities.Activity,Kernel32.TlsGetValue(activity)));
  193. END RestoreActivity;
  194. PROCEDURE Initialize-;
  195. VAR trace: ARRAY 32 OF CHAR;
  196. BEGIN {UNCOOPERATIVE, UNCHECKED}
  197. activity := Kernel32.TlsAlloc();
  198. heap := Kernel32.GetProcessHeap();
  199. stdout := Kernel32.GetStdHandle(Kernel32.STDOutput);
  200. ToExecutablePath(DefaultConfigFile, defaultConfigFile);
  201. ToExecutablePath(UserConfigFile, userConfigFile);
  202. Trace.Init;
  203. traceName[0] := 0X;
  204. Trace.Char := OutputChar;
  205. GetString("Trace",trace);
  206. IF trace = "File" THEN
  207. traceName := "SystemTrace.txt";
  208. SetupTraceName(traceName);
  209. Trace.String("trace -> file "); Trace.String(traceName); Trace.Ln;
  210. stdout := Kernel32.CreateFile(traceName, {Kernel32.GenericWrite}, {Kernel32.FileShareRead}, NIL, Kernel32.CreateAlways, {Kernel32.FileAttributeNormal}, Kernel32.NULL);
  211. Kernel32.GetFullPathName(traceName, LEN(traceName), traceName, NIL);
  212. Trace.Char := WriteChar;
  213. ELSIF trace = "Console" THEN
  214. Trace.String("trace -> console"); Trace.Ln;
  215. Kernel32.AllocConsole ();
  216. stdin:= Kernel32.GetStdHandle (Kernel32.STDInput);
  217. stdout := Kernel32.GetStdHandle (Kernel32.STDOutput);
  218. Trace.Char := WriteChar; Trace.Color := SetConsoleColor;
  219. END;
  220. END Initialize;
  221. PROCEDURE Terminate-;
  222. BEGIN {UNCOOPERATIVE, UNCHECKED}
  223. Kernel32.TlsFree(activity);
  224. END Terminate;
  225. BEGIN
  226. Trace.String ("Build "); Trace.String (SYSTEM.Date); Trace.String (" (Windows, ");
  227. Trace.String ("GC, ");
  228. Trace.Int (Processors.count, 0); Trace.String (" CPU");
  229. IF Processors.count > 1 THEN Trace.Char ('s') END; Trace.String (", ");
  230. Trace.Int (SIZE OF ADDRESS * 8, 0); Trace.String ("-bit)"); Trace.Ln;
  231. ASSERT (Kernel32.CreateThread (NIL, 0, TimerThread, NIL, {}, NIL) # Kernel32.InvalidHandleValue);
  232. END Environment.