system.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2004 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. System.pp for Netware libc environment
  10. **********************************************************************}
  11. { no stack check in system }
  12. {$S-}
  13. unit System;
  14. interface
  15. {$define FPC_IS_SYSTEM}
  16. {$define netware}
  17. {$define netware_libc}
  18. {$define StdErrToConsole}
  19. {$define autoHeapRelease}
  20. {$define IOpossix}
  21. {$define DisableArrayOfConst}
  22. {$define DISABLE_NO_THREAD_MANAGER}
  23. {$ifdef SYSTEMDEBUG}
  24. {$define SYSTEMEXCEPTIONDEBUG}
  25. {$endif SYSTEMDEBUG}
  26. {$ifdef cpui386}
  27. {$define Set_i386_Exception_handler}
  28. {$endif cpui386}
  29. { include system-independent routine headers }
  30. {$I systemh.inc}
  31. {Platform specific information}
  32. const
  33. LineEnding = #13#10;
  34. LFNSupport : boolean = false;
  35. DirectorySeparator = '/';
  36. DriveSeparator = ':';
  37. ExtensionSeparator = '.';
  38. PathSeparator = ';';
  39. AllowDirectorySeparators : set of char = ['\','/'];
  40. AllowDriveSeparators : set of char = [':'];
  41. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  42. maxExitCode = $ffff;
  43. MaxPathLen = 256;
  44. AllFilesMask = '*';
  45. CONST
  46. { Default filehandles }
  47. UnusedHandle : THandle = -1;
  48. StdInputHandle : THandle = 0;
  49. StdOutputHandle : THandle = 0;
  50. StdErrorHandle : THandle = 0;
  51. FileNameCaseSensitive : boolean = false;
  52. FileNameCasePreserving: boolean = true;
  53. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  54. sLineBreak = LineEnding;
  55. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  56. type
  57. TNWCheckFunction = procedure (var code : longint);
  58. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  59. TDLL_Entry_Hook = procedure (dllparam : longint);
  60. VAR
  61. ArgC : INTEGER;
  62. ArgV : ppchar;
  63. NetwareCheckFunction: TNWCheckFunction;
  64. NWLoggerScreen : pointer = nil;
  65. const
  66. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  67. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  68. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  69. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  70. NetwareUnloadProc : pointer = nil; {like exitProc but for nlm unload only}
  71. envp : ppchar = nil;
  72. type
  73. //TSysCloseAllRemainingSemaphores = procedure;
  74. TSysReleaseThreadVars = procedure;
  75. TSysSetThreadDataAreaPtr = function (newPtr:pointer):pointer;
  76. procedure NWSysSetThreadFunctions (atv:TSysReleaseThreadVars;
  77. rtv:TSysReleaseThreadVars;
  78. stdata:TSysSetThreadDataAreaPtr);
  79. procedure _ConsolePrintf (s :shortstring);
  80. procedure _ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  81. procedure _ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  82. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  83. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  84. procedure _ConsolePrintf (FormatStr : PCHAR);
  85. procedure __EnterDebugger;cdecl;external '!netware' name 'EnterDebugger';
  86. function NWGetCodeStart : pointer; // needed for Lineinfo
  87. function NWGetCodeLength : dword;
  88. function NWGetDataStart : pointer;
  89. function NWGetDataLength : dword;
  90. implementation
  91. { Indicate that stack checking is taken care by OS}
  92. {$DEFINE NO_GENERIC_STACK_CHECK}
  93. { include system independent routines }
  94. {$I system.inc}
  95. procedure PASCALMAIN;external name 'PASCALMAIN';
  96. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  97. {*****************************************************************************
  98. System Dependent Exit code
  99. *****************************************************************************}
  100. var SigTermHandlerActive : boolean;
  101. Procedure system_exit;
  102. begin
  103. if TerminatingThreadID <> 0 then
  104. if TerminatingThreadID <> ThreadId then
  105. if TerminatingThreadID <> dword(pthread_self) then
  106. begin
  107. {$ifdef DEBUG_MT}
  108. _ConsolePrintf ('Terminating Thread %x because halt was called while Thread %x terminates nlm'#13#10,dword(pthread_self),TerminatingThreadId);
  109. {$endif}
  110. pthread_exit (nil);
  111. // only for the case ExitThread fails
  112. while true do
  113. NXThreadYield;
  114. end;
  115. if assigned (ReleaseThreadVars) then ReleaseThreadVars;
  116. {$ifdef autoHeapRelease}
  117. FreeSbrkMem; { free memory allocated by heapmanager }
  118. {$endif}
  119. if not SigTermHandlerActive then
  120. begin
  121. if Erroraddr <> nil then { otherwise we dont see runtime-errors }
  122. SetScreenMode (0);
  123. _exit (ExitCode);
  124. end;
  125. end;
  126. {*****************************************************************************
  127. Stack check code
  128. *****************************************************************************}
  129. const StackErr : boolean = false;
  130. procedure fpc_stackcheck(stack_size:SizeUInt);[public,alias:'FPC_STACKCHECK']; compilerproc;
  131. {
  132. called when trying to get local stack if the compiler directive $S
  133. is set this function must preserve all registers
  134. With a 5k byte safe area used to write to StdIo and some libc
  135. functions without crossing the stack boundary
  136. }
  137. begin
  138. if StackErr then exit; // avoid recursive calls
  139. asm
  140. pusha
  141. end;
  142. stackerr := (stackavail < stack_size + 5120); // we really need that much, at least on nw6.5
  143. asm
  144. popa
  145. end;
  146. if not StackErr then exit;
  147. StackErr := true;
  148. HandleError (202);
  149. end;
  150. {*****************************************************************************
  151. ParamStr/Randomize
  152. *****************************************************************************}
  153. { number of args }
  154. function paramcount : longint;
  155. begin
  156. paramcount := argc - 1;
  157. end;
  158. { argument number l }
  159. function paramstr(l : longint) : string;
  160. begin
  161. if (l>=0) and (l+1<=argc) then
  162. begin
  163. paramstr:=strpas(argv[l]);
  164. if l = 0 then // fix nlm path
  165. begin
  166. DoDirSeparators(paramstr);
  167. end;
  168. end else
  169. paramstr:='';
  170. end;
  171. { set randseed to a new pseudo random value }
  172. procedure randomize;
  173. begin
  174. randseed := time (NIL);
  175. end;
  176. {*****************************************************************************
  177. Thread Handling
  178. *****************************************************************************}
  179. { if return-value is <> 0, netware shows the message
  180. Unload Anyway ?
  181. To Disable unload at all, SetNLMDontUnloadFlag can be used on
  182. Netware >= 4.0 }
  183. function CheckFunction : longint; CDECL; [public,alias: '_NonAppCheckUnload'];
  184. var oldPtr : pointer;
  185. begin
  186. //_ConsolePrintf ('CheckFunction'#13#10);
  187. if assigned (NetwareCheckFunction) then
  188. begin
  189. if assigned (SetThreadDataAreaPtr) then
  190. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  191. result := 0;
  192. NetwareCheckFunction (result);
  193. if assigned (SetThreadDataAreaPtr) then
  194. SetThreadDataAreaPtr (oldPtr);
  195. end else
  196. result := 0;
  197. end;
  198. procedure _ConsolePrintf (s : shortstring);
  199. begin
  200. if length(s) > 254 then
  201. byte(s[0]) := 254;
  202. s := s + #0;
  203. _ConsolePrintf (@s[1]);
  204. end;
  205. procedure _ConsolePrintf (FormatStr : PCHAR);
  206. begin
  207. if NWLoggerScreen = nil then
  208. NWLoggerScreen := getnetwarelogger;
  209. if NWLoggerScreen <> nil then
  210. screenprintf (NWLoggerScreen,FormatStr);
  211. end;
  212. procedure _ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  213. begin
  214. if NWLoggerScreen = nil then
  215. NWLoggerScreen := getnetwarelogger;
  216. if NWLoggerScreen <> nil then
  217. screenprintf (NWLoggerScreen,FormatStr,Param);
  218. end;
  219. procedure _ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  220. begin
  221. _ConsolePrintf (FormatStr,longint(Param));
  222. end;
  223. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  224. begin
  225. if NWLoggerScreen = nil then
  226. NWLoggerScreen := getnetwarelogger;
  227. if NWLoggerScreen <> nil then
  228. screenprintf (NWLoggerScreen,FormatStr,P1,P2);
  229. end;
  230. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  231. begin
  232. if NWLoggerScreen = nil then
  233. NWLoggerScreen := getnetwarelogger;
  234. if NWLoggerScreen <> nil then
  235. screenprintf (NWLoggerScreen,FormatStr,P1,P2,P3);
  236. end;
  237. var NWUts : Tutsname;
  238. procedure getCodeAddresses;
  239. begin
  240. if Fpuname(NWUts) < 0 then
  241. FillChar(NWuts,sizeof(NWUts),0);
  242. end;
  243. function NWGetCodeStart : pointer;
  244. begin
  245. NWGetCodeStart := NWUts.codeoffset;
  246. NXThreadYield;
  247. end;
  248. function NWGetCodeLength : dword;
  249. begin
  250. NWGetCodeLength := NWUts.codelength;
  251. NXThreadYield;
  252. end;
  253. function NWGetDataStart : pointer;
  254. begin
  255. NWGetDataStart := NWUts.dataoffset;
  256. NXThreadYield;
  257. end;
  258. function NWGetDataLength : dword;
  259. begin
  260. NWGetDataLength := NWUts.datalength;
  261. NXThreadYield;
  262. end;
  263. {$ifdef StdErrToConsole}
  264. var ConsoleBuff : array [0..512] of char;
  265. Function ConsoleWrite(Var F: TextRec): Integer;
  266. var
  267. i : longint;
  268. Begin
  269. if F.BufPos>0 then
  270. begin
  271. if F.BufPos>sizeof(ConsoleBuff)-1 then
  272. i:=sizeof(ConsoleBuff)-1
  273. else
  274. i:=F.BufPos;
  275. Move(F.BufPtr^,ConsoleBuff,i);
  276. ConsoleBuff[i] := #0;
  277. screenprintf (NWLoggerScreen,@ConsoleBuff);
  278. end;
  279. F.BufPos:=0;
  280. ConsoleWrite := 0;
  281. NXThreadYield;
  282. End;
  283. Function ConsoleClose(Var F: TextRec): Integer;
  284. begin
  285. ConsoleClose:=0;
  286. end;
  287. Function ConsoleOpen(Var F: TextRec): Integer;
  288. Begin
  289. TextRec(F).InOutFunc:=@ConsoleWrite;
  290. TextRec(F).FlushFunc:=@ConsoleWrite;
  291. TextRec(F).CloseFunc:=@ConsoleClose;
  292. ConsoleOpen:=0;
  293. End;
  294. procedure AssignStdErrConsole(Var T: Text);
  295. begin
  296. Assign(T,'');
  297. TextRec(T).OpenFunc:=@ConsoleOpen;
  298. Rewrite(T);
  299. end;
  300. {$endif}
  301. function GetProcessID: SizeUInt;
  302. begin
  303. GetProcessID := SizeUInt (getnlmhandle);
  304. end;
  305. { this will be called if the nlm is unloaded. It will NOT be
  306. called if the program exits i.e. with halt.
  307. Halt (or _exit) can not be called from this callback procedure }
  308. procedure TermSigHandler (Sig:longint); CDecl;
  309. var oldPtr : pointer;
  310. current_exit : procedure;
  311. begin
  312. { Threadvar Pointer will not be valid because the signal
  313. handler is called by netware with a differnt thread. To avoid
  314. problems in the exit routines, we set the data of the main thread
  315. here }
  316. if assigned (SetThreadDataAreaPtr) then
  317. oldPtr := SetThreadDataAreaPtr (NIL); { nil means main thread }
  318. TerminatingThreadID := dword(pthread_self);
  319. {we need to finalize winock to release threads
  320. waiting on a blocking socket call. If that thread
  321. calls halt, we have to avoid that unit finalization
  322. is called by that thread because we are doing it
  323. here
  324. like the old exitProc, mainly to allow winsock to release threads
  325. blocking in a winsock calls }
  326. while NetwareUnloadProc<>nil Do
  327. Begin
  328. InOutRes:=0;
  329. current_exit:=tProcedure(NetwareUnloadProc);
  330. NetwareUnloadProc:=nil;
  331. current_exit();
  332. NXThreadYield;
  333. //hadExitProc := true;
  334. End;
  335. SigTermHandlerActive := true; { to avoid that system_exit calls _exit }
  336. do_exit; { calls finalize units }
  337. if assigned (SetThreadDataAreaPtr) then
  338. SetThreadDataAreaPtr (oldPtr);
  339. end;
  340. procedure SysInitStdIO;
  341. begin
  342. { Setup stdin, stdout and stderr }
  343. {$ifdef IOpossix}
  344. StdInputHandle := THandle (fileno (___stdin^)); // GetStd** returns **FILE !
  345. StdOutputHandle:= THandle (fileno (___stdout^));
  346. StdErrorHandle := THandle (fileno (___stderr^));
  347. {$else}
  348. StdInputHandle := THandle (___stdin^); // GetStd** returns **FILE !
  349. StdOutputHandle:= THandle (___stdout^);
  350. StdErrorHandle := THandle (___stderr^);
  351. {$endif}
  352. OpenStdIO(Input,fmInput,StdInputHandle);
  353. OpenStdIO(Output,fmOutput,StdOutputHandle);
  354. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  355. {$ifdef StdErrToConsole}
  356. AssignStdErrConsole(StdErr);
  357. AssignStdErrConsole(ErrOutput);
  358. {$else}
  359. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  360. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  361. {$endif}
  362. end;
  363. // this is called by main.as, setup args and call PASCALMAIN
  364. procedure nlm_main (_ArgC : LONGINT; _ArgV : ppchar); cdecl; [public,alias: '_FPC_NLM_Entry'];
  365. BEGIN
  366. ArgC := _ArgC;
  367. ArgV := _ArgV;
  368. isLibrary := false;
  369. PASCALMAIN;
  370. do_exit; // currently not needed
  371. END;
  372. function _DLLMain (hInstDLL:pointer; fdwReason:dword; DLLParam:longint):longbool; cdecl;
  373. [public, alias : '_FPC_DLL_Entry'];
  374. var res : longbool;
  375. begin
  376. {$ifdef DEBUG_MT}
  377. _ConsolePrintf ('_FPC_DLL_Entry called');
  378. {$endif}
  379. _DLLMain := false;
  380. isLibrary := true;
  381. case fdwReason of
  382. DLL_ACTUAL_DLLMAIN : _DLLMain := true;
  383. DLL_NLM_STARTUP : begin
  384. //_ConsolePrintf ('DLL_NLM_STARTUP');
  385. if assigned(Dll_Process_Attach_Hook) then
  386. begin
  387. res:=Dll_Process_Attach_Hook(DllParam);
  388. if not res then
  389. exit(false);
  390. end;
  391. PASCALMAIN;
  392. _DLLMain := true;
  393. end;
  394. DLL_NLM_SHUTDOWN : begin
  395. //_ConsolePrintf ('DLL_NLM_SHUTDOWN');
  396. TermSigHandler(0);
  397. _DLLMain := true;
  398. end;
  399. { standard DllMain() messages... }
  400. DLL_THREAD_ATTACH,
  401. DLL_PROCESS_ATTACH : begin
  402. //__ConsolePrintf ('DLL_PROCESS/THREAD_ATTACH');
  403. if assigned(AllocateThreadVars) then
  404. AllocateThreadVars;
  405. if assigned(Dll_Thread_Attach_Hook) then
  406. Dll_Thread_Attach_Hook(DllParam);
  407. _DLLMain := true;
  408. end;
  409. DLL_THREAD_DETACH,
  410. DLL_PROCESS_DETACH : begin
  411. //__ConsolePrintf ('DLL_PROCESS/THREAD_DETACH');
  412. if assigned(Dll_Thread_Detach_Hook) then
  413. Dll_Thread_Detach_Hook(DllParam);
  414. if assigned(ReleaseThreadVars) then
  415. ReleaseThreadVars;
  416. _DLLMain := true;
  417. end;
  418. end;
  419. end;
  420. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  421. begin
  422. result := stklen;
  423. end;
  424. {*****************************************************************************
  425. SystemUnit Initialization
  426. *****************************************************************************}
  427. Begin
  428. getCodeAddresses;
  429. StackLength := CheckInitialStkLen(initialStkLen);
  430. StackBottom := SPtr - StackLength;
  431. SigTermHandlerActive := false;
  432. NetwareCheckFunction := nil;
  433. {$ifdef StdErrToConsole}
  434. NWLoggerScreen := getnetwarelogger;
  435. {$endif}
  436. CheckFunction; // avoid check function to be removed by the linker
  437. envp := ____environ^;
  438. NLMHandle := getnlmhandle;
  439. { allocate resource tags to see what kind of memory i forgot to release }
  440. HeapAllocResourceTag :=
  441. AllocateResourceTag(NLMHandle,'Heap Memory',AllocSignature);
  442. {$ifdef autoHeapRelease}
  443. HeapListAllocResourceTag :=
  444. AllocateResourceTag(NLMHandle,'Heap Memory List',AllocSignature);
  445. {$endif}
  446. FpSignal (SIGTERM, @TermSigHandler);
  447. { Setup heap }
  448. InitHeap;
  449. SysInitExceptions;
  450. { Reset IO Error }
  451. InOutRes:=0;
  452. ThreadID := dword(pthread_self);
  453. initunicodestringmanager;
  454. SysInitStdIO;
  455. {Delphi Compatible}
  456. IsConsole := TRUE;
  457. ExitCode := 0;
  458. InitSystemThreads;
  459. InitSystemDynLibs;
  460. End.