system.pp 15 KB

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