// Cross-platform "where did it hang?" logger. Holds joeylog.txt open // across calls; libc's stdio buffer absorbs writes (~4 KB) and the // final fclose at program exit (via atexit) gets the buffer to disk. // // Earlier rev opened+closed per call for crash durability ("last line // guaranteed on disk if we hang"); that cost ~1 second per call // through GoldenGate's ProDOS FST emulation -- a 50-line UBER run // burned ~5 minutes in IO. Even per-line fflush is too expensive // because every fflush forces an FST WRITE, and host-OS file IO time // isn't tracked by the IIgs VBL counter so wall-time logs underreport. // // Tradeoff: if the program crashes mid-run, buffered log lines may // not reach disk. For UBER and similar batch demos that's acceptable; // for hang-debugging where durability matters, call joeyLogFlush() // at the suspected hang points. #include #include #include "joey/platform.h" #include "joey/debug.h" static const char *kLogPath = "joeylog.txt"; static FILE *gLogFp = NULL; /* 16 KB is enough for UBER's full log (~5 KB) plus generous headroom, * so the file never auto-flushes mid-run. ORCA-C / libnix default * buffers are only ~512 bytes; with that, a 50-line log triggers ~10 * ProDOS / AmigaDOS WRITEs through the host FST, each of which is * untracked-host-time (seconds). Buffer the whole thing in memory and * let the atexit fclose flush once. */ #define JOEY_LOG_BUF_BYTES 16384 static char gLogBuf[JOEY_LOG_BUF_BYTES]; /* Lazy-open. Returns NULL if the open failed (silently disable). */ static FILE *logFile(void) { if (gLogFp == NULL) { gLogFp = fopen(kLogPath, "a"); if (gLogFp != NULL) { (void)setvbuf(gLogFp, gLogBuf, _IOFBF, sizeof(gLogBuf)); } } return gLogFp; } void joeyLog(const char *msg) { FILE *fp; if (msg == NULL) { return; } fp = logFile(); if (fp == NULL) { return; } fputs(msg, fp); fputc('\n', fp); } void joeyLogF(const char *fmt, ...) { FILE *fp; va_list args; if (fmt == NULL) { return; } fp = logFile(); if (fp == NULL) { return; } va_start(args, fmt); vfprintf(fp, fmt, args); va_end(args); fputc('\n', fp); } void joeyLogFlush(void) { if (gLogFp != NULL) { fflush(gLogFp); } } void joeyLogReset(void) { if (gLogFp != NULL) { fclose(gLogFp); gLogFp = NULL; } /* Truncate by opening for write then closing; subsequent * joeyLog* will reopen for append. */ { FILE *fp = fopen(kLogPath, "w"); if (fp != NULL) { fclose(fp); } } }