system.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2004 by the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. System.pp for Netware libc environment
  11. **********************************************************************}
  12. { no stack check in system }
  13. {$S-}
  14. unit system;
  15. interface
  16. {$define netware}
  17. {$define netware_libc}
  18. {$define StdErrToConsole}
  19. {$define autoHeapRelease}
  20. {$define IOpossix}
  21. {$define DisableArrayOfConst}
  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. CONST
  41. { Default filehandles }
  42. UnusedHandle : THandle = -1;
  43. StdInputHandle : THandle = 0;
  44. StdOutputHandle : THandle = 0;
  45. StdErrorHandle : THandle = 0;
  46. FileNameCaseSensitive : boolean = false;
  47. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  48. sLineBreak = LineEnding;
  49. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  50. type
  51. TNWCheckFunction = procedure (var code : longint);
  52. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  53. TDLL_Entry_Hook = procedure (dllparam : longint);
  54. VAR
  55. ArgC : INTEGER;
  56. ArgV : ppchar;
  57. NetwareCheckFunction: TNWCheckFunction;
  58. NWLoggerScreen : pointer = nil;
  59. const
  60. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  61. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  62. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  63. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  64. NetwareUnloadProc : pointer = nil; {like exitProc but for nlm unload only}
  65. envp : ppchar = nil;
  66. type
  67. //TSysCloseAllRemainingSemaphores = procedure;
  68. TSysReleaseThreadVars = procedure;
  69. TSysSetThreadDataAreaPtr = function (newPtr:pointer):pointer;
  70. procedure NWSysSetThreadFunctions (atv:TSysReleaseThreadVars;
  71. rtv:TSysReleaseThreadVars;
  72. stdata:TSysSetThreadDataAreaPtr);
  73. procedure _ConsolePrintf (s :shortstring);
  74. procedure _ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  75. procedure _ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  76. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  77. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  78. procedure _ConsolePrintf (FormatStr : PCHAR);
  79. procedure __EnterDebugger;cdecl;external '!netware' name 'EnterDebugger';
  80. function NWGetCodeStart : pointer; // needed for Lineinfo
  81. function NWGetCodeLength : dword;
  82. function NWGetDataStart : pointer;
  83. function NWGetDataLength : dword;
  84. implementation
  85. { Indicate that stack checking is taken care by OS}
  86. {$DEFINE NO_GENERIC_STACK_CHECK}
  87. { include system independent routines }
  88. {$I system.inc}
  89. procedure PASCALMAIN;external name 'PASCALMAIN';
  90. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  91. {*****************************************************************************
  92. System Dependent Exit code
  93. *****************************************************************************}
  94. var SigTermHandlerActive : boolean;
  95. Procedure system_exit;
  96. begin
  97. if TerminatingThreadID <> 0 then
  98. if TerminatingThreadID <> ThreadId then
  99. if TerminatingThreadID <> dword(pthread_self) then
  100. begin
  101. {$ifdef DEBUG_MT}
  102. _ConsolePrintf ('Terminating Thread %x because halt was called while Thread %x terminates nlm'#13#10,dword(pthread_self),TerminatingThreadId);
  103. {$endif}
  104. pthread_exit (nil);
  105. // only for the case ExitThread fails
  106. while true do
  107. NXThreadYield;
  108. end;
  109. if assigned (ReleaseThreadVars) then ReleaseThreadVars;
  110. {$ifdef autoHeapRelease}
  111. FreeSbrkMem; { free memory allocated by heapmanager }
  112. {$endif}
  113. if not SigTermHandlerActive then
  114. begin
  115. if Erroraddr <> nil then { otherwise we dont see runtime-errors }
  116. SetScreenMode (0);
  117. _exit (ExitCode);
  118. end;
  119. end;
  120. {*****************************************************************************
  121. Stack check code
  122. *****************************************************************************}
  123. const StackErr : boolean = false;
  124. procedure int_stackcheck(stack_size:Cardinal);[public,alias:'FPC_STACKCHECK'];
  125. {
  126. called when trying to get local stack if the compiler directive $S
  127. is set this function must preserve all registers
  128. With a 5k byte safe area used to write to StdIo and some libc
  129. functions without crossing the stack boundary
  130. }
  131. begin
  132. if StackErr then exit; // avoid recursive calls
  133. asm
  134. pusha
  135. end;
  136. stackerr := (stackavail < stack_size + 5120); // we really need that much, at least on nw6.5
  137. asm
  138. popa
  139. end;
  140. if not StackErr then exit;
  141. StackErr := true;
  142. HandleError (202);
  143. end;
  144. {*****************************************************************************
  145. ParamStr/Randomize
  146. *****************************************************************************}
  147. { number of args }
  148. function paramcount : longint;
  149. begin
  150. paramcount := argc - 1;
  151. end;
  152. { argument number l }
  153. function paramstr(l : longint) : string;
  154. begin
  155. if (l>=0) and (l+1<=argc) then
  156. begin
  157. paramstr:=strpas(argv[l]);
  158. if l = 0 then // fix nlm path
  159. begin
  160. for l := 1 to length (paramstr) do
  161. if paramstr[l] = '\' then paramstr[l] := '/';
  162. end;
  163. end else
  164. paramstr:='';
  165. end;
  166. { set randseed to a new pseudo random value }
  167. procedure randomize;
  168. begin
  169. randseed := time (NIL);
  170. end;
  171. {*****************************************************************************
  172. Thread Handling
  173. *****************************************************************************}
  174. procedure InitFPU;assembler;
  175. asm
  176. fninit
  177. fldcw fpucw
  178. end;
  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. {*****************************************************************************
  421. SystemUnit Initialization
  422. *****************************************************************************}
  423. Begin
  424. getCodeAddresses;
  425. StackBottom := SPtr - StackLength;
  426. SigTermHandlerActive := false;
  427. NetwareCheckFunction := nil;
  428. {$ifdef StdErrToConsole}
  429. NWLoggerScreen := getnetwarelogger;
  430. {$endif}
  431. CheckFunction; // avoid check function to be removed by the linker
  432. envp := ____environ^;
  433. NLMHandle := getnlmhandle;
  434. { allocate resource tags to see what kind of memory i forgot to release }
  435. HeapAllocResourceTag :=
  436. AllocateResourceTag(NLMHandle,'Heap Memory',AllocSignature);
  437. {$ifdef autoHeapRelease}
  438. HeapListAllocResourceTag :=
  439. AllocateResourceTag(NLMHandle,'Heap Memory List',AllocSignature);
  440. {$endif}
  441. FpSignal (SIGTERM, @TermSigHandler);
  442. { Setup heap }
  443. InitHeap;
  444. SysInitExceptions;
  445. { Reset IO Error }
  446. InOutRes:=0;
  447. ThreadID := dword(pthread_self);
  448. SysInitStdIO;
  449. {Delphi Compatible}
  450. IsConsole := TRUE;
  451. ExitCode := 0;
  452. InitSystemThreads;
  453. {$ifdef HASVARIANT}
  454. initvariantmanager;
  455. {$endif HASVARIANT}
  456. {$ifdef HASWIDESTRING}
  457. initwidestringmanager;
  458. {$endif HASWIDESTRING}
  459. End.
  460. {
  461. $Log$
  462. Revision 1.16 2005-05-12 20:29:04 michael
  463. + Added maxpathlen constant (maximum length of filename path)
  464. Revision 1.15 2005/04/03 21:10:59 hajny
  465. * EOF_CTRLZ conditional define replaced with CtrlZMarksEOF, #26 handling made more consistent (fix for bug 2453)
  466. Revision 1.14 2005/02/14 17:13:30 peter
  467. * truncate log
  468. Revision 1.13 2005/02/06 16:57:18 peter
  469. * threads for go32v2,os,emx,netware
  470. Revision 1.12 2005/02/01 20:22:49 florian
  471. * improved widestring infrastructure manager
  472. Revision 1.11 2005/01/04 11:25:34 armin
  473. * rtl code cleanup, compat fixes between clib and libc
  474. }