home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Stuart's Tech Notes / Event Logger / EventLog.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-26  |  7.4 KB  |  260 lines  |  [TEXT/KAHL]

  1. #include <stdio.h>
  2. #include <stdarg.h>
  3.  
  4. #include <StuTypes.h>
  5.  
  6. #include "Utils.h"
  7. #include "EventLog.h"
  8.  
  9. #define buffer_size 0x8000L
  10. #define buffer_limit (buffer_size - 0x100)
  11. #define TIMER_SEED (-100000000)
  12.  
  13. local void primetimer(TMTask *task)
  14.     {
  15.     task->tmAddr     = NULL;
  16.     task->tmCount    = 0;
  17.     task->tmWakeUp   = 0;
  18.     task->tmReserved = 0;
  19.     InsTime((QElemPtr)task);
  20.     PrimeTime((QElemPtr)task, TIMER_SEED);
  21.     }
  22.  
  23. local long readtimer(TMTask *task)
  24.     {
  25.     long interval;
  26.     RmvTime((QElemPtr)task);
  27.     interval = task->tmCount - TIMER_SEED;
  28.     if (interval == -TIMER_SEED) return(-1); else return(interval);
  29.     }
  30.  
  31. local Boolean WritingData(EventLog *e)
  32.     {
  33.     Boolean x;
  34.     InterruptStatus statusregister = DisableInterrupts();
  35.     x = (e->savingbuffer->pb.ioResult == 1);
  36.     RestoreInterrupts(statusregister);
  37.     return(x);
  38.     }
  39.  
  40. local pascal void WriteComplete(void);
  41. local void writelog(EventLog *e)
  42.     {
  43.     InterruptStatus statusregister = DisableInterrupts();
  44.     
  45.     // Note: Even though it may seem wierd to flush the file and volume BEFORE
  46.     // we do the write, remember that after the write actually completes, the
  47.     // WriteComplete routine calls writelog again to actually flush the data to disk.
  48.     // Also have to take care here in case PBFlushFile or PBFlushVol cause the completion
  49.     // of our last write, which will result in a reentrant call of writelog even though
  50.     // interrupts are disabled.
  51.     // Further note: This code to flush the file out was an attempt to provide
  52.     // the best possible post-mortem crash diagnosis right up to the moment before
  53.     // the crash, but it doesn't work (the disk driver seems to cache stuff anyway)
  54.     // and it may even have been responsible for some of the crashes
  55.     if (0 && e->fileflusher.ioResult == noErr)
  56.         {
  57.         e->fileflusher.ioResult = 1;
  58.         PBFlushFile((ParmBlkPtr)&e->fileflusher, TRUE);
  59.         }
  60.     if (0 && e->volflusher.ioResult == noErr)
  61.         {
  62.         e->volflusher.ioResult = 1;
  63.         PBFlushVol((ParmBlkPtr)&e->volflusher, TRUE);
  64.         }
  65.  
  66.     if (e->fRefNum && e->savingbuffer->pb.ioResult == noErr &&
  67.         e->ptr > e->loggingbuffer->buffer)
  68.         {
  69.         LogBuffer *b = e->loggingbuffer;
  70.         if (e->overflow)
  71.             {
  72.             e->overflow = FALSE;
  73.             if (e->ptr < e->loggingbuffer->buffer + buffer_size - 32)
  74.                 e->ptr += sprintf((char*)e->ptr, "*** Log Buffer Overflow ***\r");
  75.             }
  76.         e->loggingbuffer = e->savingbuffer;
  77.         e->savingbuffer = b;
  78.         //WriteCompleteUP.routineRecords[0].procDescriptor = WriteComplete;
  79.         b->pb.ioCompletion = WriteComplete;
  80.         b->pb.ioRefNum     = e->fRefNum;
  81.         b->pb.ioBuffer     = (Ptr)b->buffer;
  82.         b->pb.ioReqCount   = e->ptr - b->buffer;
  83.         b->pb.ioPosMode    = fsAtMark | fsNoCache;
  84.         b->pb.ioPosOffset  = 0;
  85.         e->ptr = e->loggingbuffer->buffer;
  86.         b->pb.ioResult = 1;
  87.         RestoreInterrupts(statusregister);
  88.         PBWrite((ParmBlkPtr)&b->pb, TRUE);
  89.         return;
  90.         // Caution: Completion routine could be invoked immediately
  91.         // within PBWrite call. Be careful about any assumptions made
  92.         // by code added here after the PBWrite call
  93.         }
  94.     RestoreInterrupts(statusregister);
  95.     }
  96.  
  97. local pascal void WriteComplete(void)
  98.     {
  99.     long *savereg;
  100.     register EventLog *e;
  101.     asm    {    move.l    GLOBREG, savereg
  102.             move.l    LogBuffer.log(a0), e
  103.             move.l    EventLog.GlobalsReg(e), GLOBREG
  104.             move.l    e, -(sp)
  105.             bsr        writelog
  106.             lea        4(sp), sp
  107.             move.l    savereg, GLOBREG
  108.         }
  109.     }
  110.  
  111. export void logevent(EventLog *e, char *format, ...)
  112.     {
  113.     InterruptStatus statusregister;
  114.     char buffer[0x100];
  115.     long length;
  116.     va_list ptr;
  117.     if (!e->fRefNum) return;
  118.     va_start(ptr,format);
  119.     length = vsprintf(buffer, format, ptr);
  120.     buffer[length++] = '\r';
  121.     if (length > 0xF0)
  122.         debug("Oops! String at %lX is %ld bytes long. Time for Reboot!", buffer, length);
  123.     va_end(ptr);
  124.     statusregister = DisableInterrupts();
  125.     if (e->ptr >= e->loggingbuffer->buffer + buffer_limit) e->overflow = TRUE;
  126.     else
  127.         {
  128.         static u_char overtime[12] = "--,---,--- ";
  129.         u_char timesting[12], *timptr = ×ting[11];
  130.         long interval = readtimer(&e->timer);
  131.         primetimer(&e->timer);
  132.         if (interval == -1) timptr = overtime;
  133.         else
  134.             {
  135.             int i;
  136.             *--timptr = ' ';
  137.             for (i=0; i<8; i++)
  138.                 {
  139.                 if (i == 3 || i == 6) *--timptr = interval ? ',' : ' ';
  140.                 if (interval == 0) *--timptr = ' ';
  141.                 else { *--timptr = '0' + interval % 10; interval /= 10; }
  142.                 }
  143.             }
  144.         BlockMoveData(timptr, e->ptr,     11); e->ptr += 11;
  145.         BlockMoveData(buffer, e->ptr, length); e->ptr += length;
  146.         }
  147.     RestoreInterrupts(statusregister);
  148.     writelog(e);
  149.     }
  150.  
  151. export void logsuppliment(EventLog *e, char *format, ...)
  152.     {
  153.     InterruptStatus statusregister;
  154.     char buffer[0x100];
  155.     Size length;
  156.     va_list ptr;
  157.     if (!e->fRefNum) return;
  158.     va_start(ptr,format);
  159.     length = sprintf(buffer, "           ");
  160.     length += vsprintf(buffer+length, format, ptr);
  161.     buffer[length++] = '\r';
  162.     if (length > 100)
  163.         debug("Oops! String at %lX is %ld bytes long. Time for Reboot!", buffer, length);
  164.     va_end(ptr);
  165.     statusregister = DisableInterrupts();
  166.     if (e->ptr >= e->loggingbuffer->buffer + buffer_limit) e->overflow = TRUE;
  167.     else { BlockMoveData(buffer, e->ptr, length); e->ptr += length; }
  168.     RestoreInterrupts(statusregister);
  169.     writelog(e);
  170.     }
  171.  
  172. export void logdata(EventLog *e, char *desc, void *data, u_short length, u_short limit)
  173.     {
  174.     u_short offset = 0;
  175.     u_char *packet = (u_char *)data;
  176.     if (!e->fRefNum) return;
  177.     logevent(e, "%s Packet length 0x%X", desc, length);
  178.     if (length > limit) length = limit;
  179.     while (offset < length)
  180.         {
  181.         int i;
  182.         char buffer[256], *ptr = buffer;
  183.         ptr += sprintf(ptr, "    %04X  ", offset);
  184.         for (i=0; i<16; i++)
  185.             {
  186.             static const char hex[16] = "0123456789ABCDEF";
  187.             if (offset+i >= length) { *ptr++ = ' '; *ptr++ = ' '; }
  188.             else
  189.                 {
  190.                 *ptr++ = hex[packet[offset+i] >> 4];
  191.                 *ptr++ = hex[packet[offset+i] & 0xF];
  192.                 }
  193.             *ptr++ = ' ';
  194.             }
  195.         for (i=0; i<16; i++)
  196.             if (offset+i < length)
  197.                 {
  198.                 if (packet[offset+i] < 32 || packet[offset+i] > 126) *ptr++ = '.';
  199.                 else *ptr++ = packet[offset+i];
  200.                 }
  201.         *ptr++ = 0;
  202.         logsuppliment(e, "%s", buffer);
  203.         offset += 0x10;
  204.         }
  205.     }
  206.  
  207. export void EventLog_Open(register EventLog *e, u_char *fileName)
  208.     {
  209.     //e->fRefNum = 0; return;
  210.     e->GlobalsReg = GetGlobalsRegister();
  211.     e->buffer1.pb.ioResult = noErr;
  212.     e->buffer1.buffer = (u_char*)NewPtrSys(buffer_size);
  213.     e->buffer1.log = e;
  214.     e->buffer2.pb.ioResult = noErr;
  215.     e->buffer2.buffer = (u_char*)NewPtrSys(buffer_size);
  216.     e->buffer2.log = e;
  217.     if (e->buffer1.buffer && e->buffer2.buffer)
  218.         {
  219.         OSErr err;
  220.         Str255 thename;
  221.         SysEnvRec system;
  222.         SysEnvirons(1, &system);
  223.         BlockMove(fileName, thename, 1+fileName[0]);
  224.         thename[fileName[0]+1] = '.';
  225.         thename[fileName[0]+2] = 'A';
  226.         e->overflow      = FALSE;
  227.         e->ptr           = e->buffer1.buffer;
  228.         e->loggingbuffer = &e->buffer1;
  229.         e->savingbuffer  = &e->buffer2;
  230.         while ((err = Create(thename, system.sysVRefNum, 'R*ch', 'TEXT')) == dupFNErr)
  231.             { thename[0] = fileName[0]+2; thename[fileName[0]+2]++; }
  232.         if (!err) err = FSOpen(thename, system.sysVRefNum, &e->fRefNum);
  233.         
  234.         e->fileflusher.ioCompletion = NULL;
  235.         e->fileflusher.ioRefNum     = e->fRefNum;
  236.         PBFlushFile((ParmBlkPtr)&e->fileflusher, FALSE);
  237.         e->volflusher.ioCompletion  = NULL;
  238.         e->volflusher.ioNamePtr     = NULL;
  239.         e->volflusher.ioVRefNum     = e->fRefNum;
  240.         PBFlushVol((ParmBlkPtr)&e->fileflusher, FALSE);
  241.         primetimer(&e->timer);
  242.         }
  243.     }
  244.  
  245. export void EventLog_Close(EventLog *e)
  246.     {
  247.     if (e->fRefNum)
  248.         {
  249.         SysEnvRec system;
  250.         SysEnvirons(1, &system);
  251.         readtimer(&e->timer);
  252.         while(WritingData(e));
  253.         FSClose(e->fRefNum);
  254.         FlushVol(NULL, system.sysVRefNum);
  255.         e->fRefNum = 0;
  256.         }
  257.     if (e->buffer1.buffer) DisposePtr((Ptr)e->buffer1.buffer);
  258.     if (e->buffer2.buffer) DisposePtr((Ptr)e->buffer2.buffer);
  259.     }
  260.