KernelLogger.Mod 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. MODULE KernelLogger; (** AUTHOR "TF"; PURPOSE "Periodically copy kernel log buffer into text"; *)
  2. IMPORT
  3. SYSTEM, KernelLog, Texts, TextUtilities, Kernel, Modules;
  4. CONST
  5. BufSize = 8192 * 16; (* Kernel buffer size *)
  6. UpdateInterval = 200; (* ms *)
  7. LocalBuf = 4096 * 2;
  8. MaxLogSize = 4*BufSize;
  9. TYPE
  10. (* periodically poll the kernel log buffer *)
  11. Logger = OBJECT
  12. VAR
  13. timer : Kernel.Timer;
  14. alive, dead, added : BOOLEAN;
  15. buf : ARRAY LocalBuf OF CHAR;
  16. bufPos : LONGINT;
  17. ch : CHAR;
  18. tw : TextUtilities.TextWriter;
  19. limitCounter, n: LONGINT;
  20. PROCEDURE &Open;
  21. BEGIN
  22. dead := FALSE; alive := TRUE;
  23. NEW(timer);
  24. NEW(tw, kernelLog);
  25. END Open;
  26. PROCEDURE Close;
  27. BEGIN {EXCLUSIVE}
  28. KernelLog.CloseBuffer;
  29. alive := FALSE; timer.Wakeup;
  30. AWAIT(dead)
  31. END Close;
  32. PROCEDURE Get() : CHAR;
  33. VAR res : CHAR;
  34. BEGIN
  35. IF (bufPos >= LocalBuf) OR (buf[bufPos] = 0X) THEN
  36. bufPos := 0;
  37. KernelLog.GetBuffer(buf)
  38. END;
  39. res := buf[bufPos];
  40. INC(bufPos);
  41. RETURN res
  42. END Get;
  43. BEGIN {ACTIVE}
  44. (* pre loading the fonts so traps can be displayed even when the disk is causing the trap *)
  45. tw.SetFontName("Courier"); tw.String("Log started");
  46. tw.SetFontName("Oberon"); tw.Ln;
  47. WHILE alive DO
  48. bufPos := 0; added := FALSE;
  49. LOOP
  50. ch := Get();
  51. IF ch # 0X THEN
  52. IF ch = 0EX THEN tw.SetFontName("Courier"); tw.SetFontColor(LONGINT(0800000FFH));
  53. ELSIF ch = 0FX THEN tw.SetFontName("Oberon"); tw.SetFontColor(0FFH);
  54. ELSIF ch = 0DX THEN (* ignore CR character - this approximates the CRLF -> LF *)
  55. ELSE tw.Char(ch); added := TRUE;
  56. END;
  57. END; (* 0X (end), 0DX (CR), 0AX (LF), 0EX (FixedFont), 0FX (NormalFont) *)
  58. IF (ch = 0X) OR ~alive THEN EXIT END;
  59. INC(limitCounter);
  60. IF limitCounter >= 1024 THEN
  61. kernelLog.AcquireWrite;
  62. n := kernelLog.GetLength();
  63. IF n > MaxLogSize THEN
  64. kernelLog.Delete(0,n-MaxLogSize);
  65. END;
  66. kernelLog.ReleaseWrite;
  67. limitCounter := 0;
  68. END;
  69. END;
  70. IF added THEN
  71. tw.Update;
  72. kernelLog.AcquireWrite;
  73. n := kernelLog.GetLength();
  74. IF n > MaxLogSize+1024 THEN
  75. kernelLog.Delete(0,n-MaxLogSize);
  76. END;
  77. kernelLog.ReleaseWrite;
  78. END;
  79. timer.Sleep(UpdateInterval);
  80. END;
  81. BEGIN {EXCLUSIVE} dead := TRUE END;
  82. END Logger;
  83. VAR
  84. logger : Logger;
  85. buf : POINTER TO ARRAY OF CHAR;
  86. kernelLog- : Texts.Text;
  87. PROCEDURE Start*;
  88. CONST OberonKernel = "Oberon-Kernel"; OberonSystem = "Oberon-System";
  89. VAR kernelLockOberon, kernelUnlockOberon, systemStopLog : PROCEDURE;
  90. BEGIN {EXCLUSIVE}
  91. IF logger # NIL THEN KernelLog.Enter; KernelLog.String("Logger already running! "); KernelLog.Exit; RETURN END;
  92. KernelLog.Enter; KernelLog.String("Starting logger"); KernelLog.Exit;
  93. NEW(buf, BufSize);
  94. IF ~KernelLog.OpenBuffer(ADDRESSOF(buf[0]), LEN(buf)) THEN
  95. (* Kill Oberon Logger *)
  96. IF Modules.ModuleByName (OberonKernel) # NIL THEN
  97. GETPROCEDURE (OberonKernel, "LockOberon", kernelLockOberon);
  98. GETPROCEDURE (OberonKernel, "UnlockOberon", kernelUnlockOberon);
  99. END;
  100. IF Modules.ModuleByName (OberonSystem) # NIL THEN
  101. GETPROCEDURE (OberonSystem, "StopLog", systemStopLog);
  102. END;
  103. IF (kernelLockOberon # NIL) & (kernelUnlockOberon # NIL) &(systemStopLog # NIL) THEN
  104. kernelLockOberon; systemStopLog; kernelUnlockOberon;
  105. KernelLog.CloseBuffer; IF KernelLog.OpenBuffer(ADDRESSOF(buf[0]), LEN(buf)) THEN
  106. KernelLog.Enter; KernelLog.String("Oberon KernelLog stopped. New buffer installed"); KernelLog.Exit
  107. END
  108. END;
  109. END;
  110. NEW(logger);
  111. END Start;
  112. PROCEDURE Stop*;
  113. BEGIN {EXCLUSIVE}
  114. IF logger # NIL THEN
  115. KernelLog.Enter; KernelLog.String("Stopping logger"); KernelLog.Exit;
  116. logger.Close; logger := NIL;
  117. KernelLog.Enter; KernelLog.String("Logger stopped"); KernelLog.Exit;
  118. END;
  119. END Stop;
  120. PROCEDURE Cleanup;
  121. BEGIN
  122. IF logger # NIL THEN
  123. KernelLog.CloseBuffer;
  124. logger.Close
  125. END
  126. END Cleanup;
  127. BEGIN
  128. NEW(kernelLog);
  129. Start;
  130. Modules.InstallTermHandler(Cleanup);
  131. END KernelLogger.
  132. KernelLogger.Start ~
  133. KernelLogger.Stop ~
  134. SystemTools.Free WMKernelLog KernelLogger ~