system.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. { no stack check in system }
  11. {$S-}
  12. unit system;
  13. interface
  14. {$define StdErrToConsole}
  15. {$define useLongNamespaceByDefault}
  16. {$define autoHeapRelease}
  17. {$ifdef SYSTEMDEBUG}
  18. {$define SYSTEMEXCEPTIONDEBUG}
  19. {$endif SYSTEMDEBUG}
  20. {$ifdef cpui386}
  21. {$define Set_i386_Exception_handler}
  22. {$endif cpui386}
  23. { include system-independent routine headers }
  24. {$I systemh.inc}
  25. {Platform specific information}
  26. const
  27. LineEnding = #13#10;
  28. LFNSupport : boolean = false;
  29. DirectorySeparator = '/';
  30. DriveSeparator = ':';
  31. ExtensionSeparator = '.';
  32. PathSeparator = ';';
  33. AllowDirectorySeparators : set of char = ['\','/'];
  34. AllowDriveSeparators : set of char = [':'];
  35. { FileNameCaseSensitive is defined separately below!!! }
  36. maxExitCode = 255;
  37. MaxPathLen = 256;
  38. AllFilesMask = '*';
  39. CONST
  40. { Default filehandles }
  41. UnusedHandle : THandle = -1;
  42. StdInputHandle : THandle = 0;
  43. StdOutputHandle : THandle = 0;
  44. StdErrorHandle : THandle = 0;
  45. FileNameCaseSensitive : boolean = false;
  46. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  47. sLineBreak = LineEnding;
  48. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  49. TYPE
  50. TNWCheckFunction = procedure (var code : longint);
  51. VAR
  52. ArgC : INTEGER;
  53. ArgV : ppchar;
  54. NetwareCheckFunction : TNWCheckFunction;
  55. NetwareMainThreadGroupID: longint;
  56. NetwareCodeStartAddress : dword;
  57. NetwareUnloadProc : pointer = nil; {like exitProc but for nlm unload only}
  58. CONST
  59. envp : ppchar = nil; {dummy to make heaptrc happy}
  60. procedure ConsolePrintf (FormatStr : PCHAR; Param : LONGINT); CDecl; external 'clib' name 'printf';
  61. procedure ConsolePrintf (FormatStr : PCHAR; Param : pchar); CDecl; external 'clib' name 'printf';
  62. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT); CDecl; external 'clib' name 'printf';
  63. procedure ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT); CDecl; external 'clib' name 'printf';
  64. procedure ConsolePrintf (FormatStr : PCHAR); CDecl; external 'clib' name 'printf';
  65. // this gives internal compiler error 200404181
  66. // procedure ConsolePrintf (FormatStr : PCHAR; Param : array of const); CDecl; EXTERNAL 'clib' name 'ConsolePrintf';
  67. procedure __EnterDebugger; cdecl; external 'clib' name 'EnterDebugger';
  68. type
  69. TSysCloseAllRemainingSemaphores = procedure;
  70. TSysReleaseThreadVars = procedure;
  71. TSysSetThreadDataAreaPtr = function (newPtr:pointer):pointer;
  72. procedure NWSysSetThreadFunctions (crs:TSysCloseAllRemainingSemaphores;
  73. rtv:TSysReleaseThreadVars;
  74. stdata:TSysSetThreadDataAreaPtr);
  75. function NWGetCodeStart : pointer; // needed for lineinfo
  76. implementation
  77. { Indicate that stack checking is taken care by OS}
  78. {$DEFINE NO_GENERIC_STACK_CHECK}
  79. { include system independent routines }
  80. {$I system.inc}
  81. //procedure __EnterDebugger; cdecl; external 'clib' name 'EnterDebugger';
  82. procedure PASCALMAIN;external name 'PASCALMAIN';
  83. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  84. {*****************************************************************************
  85. Startup
  86. *****************************************************************************}
  87. function __GetBssStart : pointer; external name '__getBssStart';
  88. function __getUninitializedDataSize : longint; external name '__getUninitializedDataSize';
  89. //function __getDataStart : longint; external name '__getDataStart';
  90. function __GetTextStart : longint; external name '__getTextStart';
  91. PROCEDURE nlm_main (_ArgC : LONGINT; _ArgV : ppchar); CDECL; [public,alias: '_nlm_main'];
  92. BEGIN
  93. // Initialize BSS
  94. if __getUninitializedDataSize > 0 then
  95. fillchar (__getBssStart^,__getUninitializedDataSize,0);
  96. NetwareCodeStartAddress := __GetTextStart;
  97. ArgC := _ArgC;
  98. ArgV := _ArgV;
  99. fpc_threadvar_relocate_proc := nil;
  100. PASCALMAIN;
  101. END;
  102. function NWGetCodeStart : pointer; // needed for lineinfo
  103. begin
  104. NWGetCodeStart := pointer(NetwareCodeStartAddress);
  105. end;
  106. {*****************************************************************************
  107. System Dependent Exit code
  108. *****************************************************************************}
  109. var SigTermHandlerActive : boolean;
  110. Procedure system_exit;
  111. begin
  112. if TerminatingThreadID <> 0 then
  113. if TerminatingThreadID <> ThreadId then
  114. if TerminatingThreadID <> _GetThreadID then
  115. begin
  116. {$ifdef DEBUG_MT}
  117. ConsolePrintf ('Terminating Thread %x because halt was called while Thread %x terminates nlm'#13#10,_GetThreadId,TerminatingThreadId);
  118. {$endif}
  119. ExitThread (EXIT_THREAD,0);
  120. // only for the case ExitThread fails
  121. while true do
  122. _ThreadSwitchWithDelay;
  123. end;
  124. if assigned (CloseAllRemainingSemaphores) then CloseAllRemainingSemaphores;
  125. if assigned (ReleaseThreadVars) then ReleaseThreadVars;
  126. {$ifdef autoHeapRelease}
  127. FreeSbrkMem; { free memory allocated by heapmanager }
  128. {$endif}
  129. if not SigTermHandlerActive then
  130. begin
  131. if ExitCode <> 0 Then { otherwise we dont see runtime-errors }
  132. _SetAutoScreenDestructionMode (false);
  133. _exit (ExitCode);
  134. end;
  135. end;
  136. {*****************************************************************************
  137. Stack check code
  138. *****************************************************************************}
  139. const StackErr : boolean = false;
  140. procedure int_stackcheck(stack_size:Cardinal);[public,alias:'FPC_STACKCHECK'];
  141. {
  142. called when trying to get local stack if the compiler directive $S
  143. is set this function must preserve all registers
  144. With a 2048 byte safe area used to write to StdIo without crossing
  145. the stack boundary
  146. }
  147. begin
  148. if StackErr then exit; // avoid recursive calls
  149. asm
  150. pusha
  151. end;
  152. stackerr := ( _stackavail < stack_size + 2048);
  153. asm
  154. popa
  155. end;
  156. if not StackErr then exit;
  157. StackErr := true;
  158. HandleError (202);
  159. end;
  160. {*****************************************************************************
  161. ParamStr/Randomize
  162. *****************************************************************************}
  163. { number of args }
  164. function paramcount : longint;
  165. begin
  166. paramcount := argc - 1;
  167. end;
  168. { argument number l }
  169. function paramstr(l : longint) : string;
  170. begin
  171. if (l>=0) and (l+1<=argc) then
  172. begin
  173. paramstr:=strpas(argv[l]);
  174. if l = 0 then // fix nlm path
  175. begin
  176. DoDirSeparators(paramstr);
  177. end;
  178. end else
  179. paramstr:='';
  180. end;
  181. { set randseed to a new pseudo random value }
  182. procedure randomize;
  183. begin
  184. randseed := _time (NIL);
  185. end;
  186. {*****************************************************************************
  187. Thread Handling
  188. *****************************************************************************}
  189. { if return-value is <> 0, netware shows the message
  190. Unload Anyway ?
  191. To Disable unload at all, SetNLMDontUnloadFlag can be used on
  192. Netware >= 4.0 }
  193. function CheckFunction : longint; CDECL; [public,alias: 'FPC_NW_CHECKFUNCTION'];
  194. var oldTG:longint;
  195. oldPtr: pointer;
  196. begin
  197. if assigned (NetwareCheckFunction) then
  198. begin
  199. { this function is called without clib context, to allow clib
  200. calls, we set the thread group id before calling the
  201. user-function }
  202. oldTG := _SetThreadGroupID (NetwareMainThreadGroupID);
  203. { to allow use of threadvars, we simply set the threadvar-memory
  204. from the main thread }
  205. if assigned (SetThreadDataAreaPtr) then
  206. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main threadvars }
  207. result := 0;
  208. NetwareCheckFunction (result);
  209. if assigned (SetThreadDataAreaPtr) then
  210. SetThreadDataAreaPtr (oldPtr);
  211. _SetThreadGroupID (oldTG);
  212. end else
  213. result := 0;
  214. end;
  215. {$ifdef StdErrToConsole}
  216. var ConsoleBuff : array [0..512] of char;
  217. Function ConsoleWrite(Var F: TextRec): Integer;
  218. var
  219. i : longint;
  220. Begin
  221. if F.BufPos>0 then
  222. begin
  223. if F.BufPos>sizeof(ConsoleBuff)-1 then
  224. i:=sizeof(ConsoleBuff)-1
  225. else
  226. i:=F.BufPos;
  227. Move(F.BufPtr^,ConsoleBuff,i);
  228. ConsoleBuff[i] := #0;
  229. ConsolePrintf(@ConsoleBuff[0]);
  230. end;
  231. F.BufPos:=0;
  232. ConsoleWrite := 0;
  233. End;
  234. Function ConsoleClose(Var F: TextRec): Integer;
  235. begin
  236. ConsoleClose:=0;
  237. end;
  238. Function ConsoleOpen(Var F: TextRec): Integer;
  239. Begin
  240. TextRec(F).InOutFunc:=@ConsoleWrite;
  241. TextRec(F).FlushFunc:=@ConsoleWrite;
  242. TextRec(F).CloseFunc:=@ConsoleClose;
  243. ConsoleOpen:=0;
  244. End;
  245. procedure AssignStdErrConsole(Var T: Text);
  246. begin
  247. Assign(T,'');
  248. TextRec(T).OpenFunc:=@ConsoleOpen;
  249. Rewrite(T);
  250. end;
  251. {$endif}
  252. { this will be called if the nlm is unloaded. It will NOT be
  253. called if the program exits i.e. with halt.
  254. Halt (or _exit) can not be called from this callback procedure }
  255. procedure TermSigHandler (Sig:longint); CDecl;
  256. var oldTG : longint;
  257. oldPtr: pointer;
  258. err : longint;
  259. current_exit : procedure;
  260. ThreadName : array [0..20] of char;
  261. HadExitProc : boolean;
  262. Count : longint;
  263. begin
  264. oldTG := _SetThreadGroupID (NetwareMainThreadGroupID); { this is only needed for nw 3.11 }
  265. { _GetThreadDataAreaPtr will not be valid because the signal
  266. handler is called by netware with a differnt thread. To avoid
  267. problems in the exit routines, we set the data of the main thread
  268. here }
  269. if assigned (SetThreadDataAreaPtr) then
  270. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  271. {this signal handler is called within the console command
  272. thread, the main thread is still running. Via NetwareUnloadProc
  273. running threads may terminate itself}
  274. TerminatingThreadID := _GetThreadID;
  275. {$ifdef DEBUG_MT}
  276. ConsolePrintf (#13'TermSigHandler Called, MainThread:%x, OurThread: %x'#13#10,ThreadId,TerminatingThreadId);
  277. if NetwareUnloadProc <> nil then
  278. ConsolePrintf (#13'Calling NetwareUnloadProcs'#13#10);
  279. {$endif}
  280. HadExitProc := false;
  281. {we need to finalize winock to release threads
  282. waiting on a blocking socket call. If that thread
  283. calls halt, we have to avoid that unit finalization
  284. is called by that thread because we are doing it
  285. here
  286. like the old exitProc, mainly to allow winsock to release threads
  287. blocking in a winsock calls }
  288. while NetwareUnloadProc<>nil Do
  289. Begin
  290. InOutRes:=0;
  291. current_exit:=tProcedure(NetwareUnloadProc);
  292. NetwareUnloadProc:=nil;
  293. current_exit();
  294. _ThreadSwitchWithDelay;
  295. hadExitProc := true;
  296. End;
  297. err := 0;
  298. if hadExitProc then
  299. begin {give the main thread a little bit of time to terminate}
  300. count := 0;
  301. repeat
  302. err := _GetThreadName(ThreadID,ThreadName);
  303. if err = 0 then _Delay (200);
  304. inc(count);
  305. until (err <> 0) or (count > 100); {about 20 seconds}
  306. {$ifdef DEBUG_MT}
  307. if err = 0 then
  308. ConsolePrintf (#13,'Main Thread not terminated'#13#10)
  309. else
  310. ConsolePrintf (#13'Main Thread has ended'#13#10);
  311. {$endif}
  312. end;
  313. if err = 0 then
  314. {$ifdef DEBUG_MT}
  315. begin
  316. err := _SuspendThread(ThreadId);
  317. ConsolePrintf (#13'SuspendThread(%x) returned %d'#13#10,ThreadId,err);
  318. end;
  319. {$else}
  320. _SuspendThread(ThreadId);
  321. {$endif}
  322. _ThreadSwitchWithDelay;
  323. {$ifdef DEBUG_MT}
  324. ConsolePrintf (#13'Calling do_exit'#13#10);
  325. {$endif}
  326. SigTermHandlerActive := true; { to avoid that system_exit calls _exit }
  327. do_exit; { calls finalize units }
  328. if assigned (SetThreadDataAreaPtr) then
  329. SetThreadDataAreaPtr (oldPtr);
  330. _SetThreadGroupID (oldTG);
  331. {$ifdef DEBUG_MT}
  332. ConsolePrintf (#13'TermSigHandler: all done'#13#10);
  333. {$endif}
  334. end;
  335. procedure SysInitStdIO;
  336. begin
  337. { Setup stdin, stdout and stderr }
  338. StdInputHandle := _fileno (LONGINT (_GetStdIn^)); // GetStd** returns **FILE
  339. StdOutputHandle:= _fileno (LONGINT (_GetStdOut^));
  340. StdErrorHandle := _fileno (LONGINT (_GetStdErr^));
  341. OpenStdIO(Input,fmInput,StdInputHandle);
  342. OpenStdIO(Output,fmOutput,StdOutputHandle);
  343. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  344. {$ifdef StdErrToConsole}
  345. AssignStdErrConsole(StdErr);
  346. AssignStdErrConsole(ErrOutput);
  347. {$else}
  348. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  349. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  350. {$endif}
  351. end;
  352. function GetProcessID: SizeUInt;
  353. begin
  354. GetProcessID := SizeUInt (GetNlmHandle);
  355. end;
  356. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  357. begin
  358. result := stklen;
  359. end;
  360. {*****************************************************************************
  361. SystemUnit Initialization
  362. *****************************************************************************}
  363. Begin
  364. StackLength := CheckInitialStkLen(initialstklen);
  365. StackBottom := SPtr - StackLength;
  366. SigTermHandlerActive := false;
  367. NetwareCheckFunction := nil;
  368. NetwareMainThreadGroupID := _GetThreadGroupID;
  369. _Signal (_SIGTERM, @TermSigHandler);
  370. {$ifdef useLongNamespaceByDefault}
  371. if _getenv ('FPC_DISABLE_LONG_NAMESPACE') = nil then
  372. begin
  373. if _SetCurrentNameSpace (NW_NS_LONG) <> 255 then
  374. begin
  375. if _SetTargetNamespace (NW_NS_LONG) <> 255 then
  376. LFNSupport := true
  377. else
  378. _SetCurrentNameSpace (NW_NS_DOS);
  379. end;
  380. end;
  381. {$endif useLongNamespaceByDefault}
  382. { Setup heap }
  383. InitHeap;
  384. SysInitExceptions;
  385. { Reset IO Error }
  386. InOutRes:=0;
  387. ThreadID := _GetThreadID;
  388. {$ifdef DEBUG_MT}
  389. ConsolePrintf (#13'Start system, ThreadID: %x'#13#10,ThreadID);
  390. {$endif}
  391. SysInitStdIO;
  392. {Delphi Compatible}
  393. IsLibrary := FALSE;
  394. IsConsole := TRUE;
  395. ExitCode := 0;
  396. InitSystemThreads;
  397. initvariantmanager;
  398. initwidestringmanager;
  399. End.