system.pp 15 KB

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