system.pp 15 KB

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