system.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  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. 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. sLineBreak = LineEnding;
  47. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  48. type
  49. TNWCheckFunction = procedure (var code : longint);
  50. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  51. TDLL_Entry_Hook = procedure (dllparam : longint);
  52. VAR
  53. ArgC : INTEGER;
  54. ArgV : ppchar;
  55. NetwareCheckFunction: TNWCheckFunction;
  56. NWLoggerScreen : pointer = nil;
  57. const
  58. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  59. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  60. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  61. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  62. NetwareUnloadProc : pointer = nil; {like exitProc but for nlm unload only}
  63. envp : ppchar = nil;
  64. type
  65. //TSysCloseAllRemainingSemaphores = procedure;
  66. TSysReleaseThreadVars = procedure;
  67. TSysSetThreadDataAreaPtr = function (newPtr:pointer):pointer;
  68. procedure NWSysSetThreadFunctions (atv:TSysReleaseThreadVars;
  69. rtv:TSysReleaseThreadVars;
  70. stdata:TSysSetThreadDataAreaPtr);
  71. procedure _ConsolePrintf (s :shortstring);
  72. procedure _ConsolePrintf (FormatStr : PCHAR; Param : LONGINT);
  73. procedure _ConsolePrintf (FormatStr : PCHAR; Param : pchar);
  74. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2 : LONGINT);
  75. procedure _ConsolePrintf (FormatStr : PCHAR; P1,P2,P3 : LONGINT);
  76. procedure _ConsolePrintf (FormatStr : PCHAR);
  77. procedure __EnterDebugger;cdecl;external '!netware' name 'EnterDebugger';
  78. function NWGetCodeStart : pointer; // needed for Lineinfo
  79. function NWGetCodeLength : dword;
  80. function NWGetDataStart : pointer;
  81. function NWGetDataLength : dword;
  82. implementation
  83. { Indicate that stack checking is taken care by OS}
  84. {$DEFINE NO_GENERIC_STACK_CHECK}
  85. { include system independent routines }
  86. {$I system.inc}
  87. procedure PASCALMAIN;external name 'PASCALMAIN';
  88. procedure fpc_do_exit;external name 'FPC_DO_EXIT';
  89. {*****************************************************************************
  90. System Dependent Exit code
  91. *****************************************************************************}
  92. var SigTermHandlerActive : boolean;
  93. Procedure system_exit;
  94. begin
  95. if TerminatingThreadID <> 0 then
  96. if TerminatingThreadID <> ThreadId then
  97. if TerminatingThreadID <> dword(pthread_self) then
  98. begin
  99. {$ifdef DEBUG_MT}
  100. _ConsolePrintf ('Terminating Thread %x because halt was called while Thread %x terminates nlm'#13#10,dword(pthread_self),TerminatingThreadId);
  101. {$endif}
  102. pthread_exit (nil);
  103. // only for the case ExitThread fails
  104. while true do
  105. NXThreadYield;
  106. end;
  107. if assigned (ReleaseThreadVars) then ReleaseThreadVars;
  108. {$ifdef autoHeapRelease}
  109. FreeSbrkMem; { free memory allocated by heapmanager }
  110. {$endif}
  111. if not SigTermHandlerActive then
  112. begin
  113. if Erroraddr <> nil then { otherwise we dont see runtime-errors }
  114. SetScreenMode (0);
  115. _exit (ExitCode);
  116. end;
  117. end;
  118. {*****************************************************************************
  119. Stack check code
  120. *****************************************************************************}
  121. const StackErr : boolean = false;
  122. procedure int_stackcheck(stack_size:Cardinal);[public,alias:'FPC_STACKCHECK'];
  123. {
  124. called when trying to get local stack if the compiler directive $S
  125. is set this function must preserve all registers
  126. With a 5k byte safe area used to write to StdIo and some libc
  127. functions without crossing the stack boundary
  128. }
  129. begin
  130. if StackErr then exit; // avoid recursive calls
  131. asm
  132. pusha
  133. end;
  134. stackerr := (stackavail < stack_size + 5120); // we really need that much, at least on nw6.5
  135. asm
  136. popa
  137. end;
  138. if not StackErr then exit;
  139. StackErr := true;
  140. HandleError (202);
  141. end;
  142. {*****************************************************************************
  143. ParamStr/Randomize
  144. *****************************************************************************}
  145. { number of args }
  146. function paramcount : longint;
  147. begin
  148. paramcount := argc - 1;
  149. end;
  150. { argument number l }
  151. function paramstr(l : longint) : string;
  152. begin
  153. if (l>=0) and (l+1<=argc) then
  154. begin
  155. paramstr:=strpas(argv[l]);
  156. if l = 0 then // fix nlm path
  157. begin
  158. for l := 1 to length (paramstr) do
  159. if paramstr[l] = '\' then paramstr[l] := '/';
  160. end;
  161. end else
  162. paramstr:='';
  163. end;
  164. { set randseed to a new pseudo random value }
  165. procedure randomize;
  166. begin
  167. randseed := time (NIL);
  168. end;
  169. {*****************************************************************************
  170. Thread Handling
  171. *****************************************************************************}
  172. procedure InitFPU;assembler;
  173. asm
  174. fninit
  175. fldcw fpucw
  176. end;
  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. {*****************************************************************************
  419. SystemUnit Initialization
  420. *****************************************************************************}
  421. Begin
  422. getCodeAddresses;
  423. StackBottom := SPtr - StackLength;
  424. SigTermHandlerActive := false;
  425. NetwareCheckFunction := nil;
  426. {$ifdef StdErrToConsole}
  427. NWLoggerScreen := getnetwarelogger;
  428. {$endif}
  429. CheckFunction; // avoid check function to be removed by the linker
  430. envp := ____environ^;
  431. NLMHandle := getnlmhandle;
  432. { allocate resource tags to see what kind of memory i forgot to release }
  433. HeapAllocResourceTag :=
  434. AllocateResourceTag(NLMHandle,'Heap Memory',AllocSignature);
  435. {$ifdef autoHeapRelease}
  436. HeapListAllocResourceTag :=
  437. AllocateResourceTag(NLMHandle,'Heap Memory List',AllocSignature);
  438. {$endif}
  439. FpSignal (SIGTERM, @TermSigHandler);
  440. { Setup heap }
  441. InitHeap;
  442. SysInitExceptions;
  443. { Reset IO Error }
  444. InOutRes:=0;
  445. ThreadID := dword(pthread_self);
  446. SysInitStdIO;
  447. {Delphi Compatible}
  448. IsConsole := TRUE;
  449. ExitCode := 0;
  450. InitSystemThreads;
  451. {$ifdef HASVARIANT}
  452. initvariantmanager;
  453. {$endif HASVARIANT}
  454. {$ifdef HASWIDESTRING}
  455. initwidestringmanager;
  456. {$endif HASWIDESTRING}
  457. End.
  458. {
  459. $Log$
  460. Revision 1.13 2005-02-06 16:57:18 peter
  461. * threads for go32v2,os,emx,netware
  462. Revision 1.12 2005/02/01 20:22:49 florian
  463. * improved widestring infrastructure manager
  464. Revision 1.11 2005/01/04 11:25:34 armin
  465. * rtl code cleanup, compat fixes between clib and libc
  466. Revision 1.10 2004/12/07 11:40:43 armin
  467. * implemented GetProcessId, defined TimeVal and TimeZone in addition to TTimeVal, TTimeZone, Makefile defaults to binutilsprefix i386-netware
  468. Revision 1.9 2004/12/05 14:36:38 hajny
  469. + GetProcessID added
  470. Revision 1.8 2004/11/25 12:38:17 armin
  471. * adapted to new compiler check for externals
  472. Revision 1.7 2004/11/04 09:32:31 peter
  473. ErrOutput added
  474. Revision 1.6 2004/10/25 18:11:49 armin
  475. * saveregisters no longer supported by compiler, for now save all registers in stackcheck
  476. Revision 1.5 2004/10/25 15:38:59 peter
  477. * compiler defined HEAP and HEAPSIZE removed
  478. Revision 1.4 2004/09/26 19:23:34 armin
  479. * exiting threads at nlm unload
  480. * renamed some libc functions
  481. Revision 1.3 2004/09/19 20:06:37 armin
  482. * removed get/free video buf from video.pp
  483. * implemented sockets
  484. * basic library support
  485. * threadvar memory leak removed
  486. * fixes (ide now starts and editor is usable)
  487. * support for lineinfo
  488. Revision 1.2 2004/09/12 20:51:22 armin
  489. * added keyboard and video
  490. * a lot of fixes
  491. Revision 1.1 2004/09/05 20:58:47 armin
  492. * first rtl version for netwlibc
  493. }