mirror of
https://github.com/mauiaaron/apple2.git
synced 2025-01-13 12:31:25 +00:00
Refactor LOG() facilities
- Enable logging to file(s) - Enable log rotation - Allow silencing console logging (e.g., to stderr)
This commit is contained in:
parent
1716dd35be
commit
bcbf5ac234
@ -14,7 +14,7 @@ noinst_HEADERS = src/common.h src/cpu.h src/disk.h src/glue.h src/vm.h \
|
||||
src/timing.h src/uthash.h src/video/video.h src/zlib-helpers.h \
|
||||
\
|
||||
src/x86/glue-prologue.h \
|
||||
src/meta/debug.h src/meta/trace.h \
|
||||
src/meta/debug.h src/meta/log.h src/meta/trace.h \
|
||||
\
|
||||
src/audio/alhelpers.h src/audio/AY8910.h src/audio/mockingboard.h \
|
||||
src/audio/peripherals.h src/audio/soundcore.h src/audio/speaker.h \
|
||||
@ -66,6 +66,7 @@ apple2ix_SOURCES = \
|
||||
src/meta/debugger.c \
|
||||
src/meta/opcodes.c \
|
||||
src/meta/lintrace.c \
|
||||
src/meta/log.c \
|
||||
src/misc.c \
|
||||
src/prefs.c \
|
||||
src/rom.c \
|
||||
|
@ -277,7 +277,6 @@ PlayQueue_s *playq_createPlayQueue(const long *nodeIdPtr, unsigned long numBuffe
|
||||
#define SELF_TEST 0
|
||||
#if SELF_TEST
|
||||
bool do_logging = true;
|
||||
FILE *error_log = NULL;
|
||||
|
||||
static void _test_creation(void) {
|
||||
LOG("begin test");
|
||||
@ -789,7 +788,6 @@ static void _test_remove_middle_of_queue(void) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#warning use Valgrind to check proper memory management
|
||||
error_log = stdout;
|
||||
LOG("beginning tests");
|
||||
_test_creation();
|
||||
_test_internal_list_creation_integrity();
|
||||
|
145
src/common.h
145
src/common.h
@ -89,21 +89,10 @@
|
||||
#endif
|
||||
|
||||
#if VIDEO_OPENGL
|
||||
#include "video_util/glUtil.h"
|
||||
// 2015/04/01 ... early calls to glGetError()--before a context exists--causes segfaults on MacOS X
|
||||
extern bool safe_to_do_opengl_logging;
|
||||
static inline GLenum safeGLGetError(void) {
|
||||
if (safe_to_do_opengl_logging && video_isRenderThread()) {
|
||||
return glGetError();
|
||||
}
|
||||
return (GLenum)0;
|
||||
}
|
||||
#else
|
||||
#define GLenum int
|
||||
#define safeGLGetError() 0
|
||||
#define glGetError() 0
|
||||
# include "video_util/glUtil.h"
|
||||
#endif
|
||||
|
||||
#include "meta/log.h"
|
||||
#include "meta/debug.h"
|
||||
|
||||
#include "audio/soundcore.h"
|
||||
@ -157,136 +146,6 @@ static inline GLenum safeGLGetError(void) {
|
||||
_rc; })
|
||||
|
||||
|
||||
extern bool do_logging;
|
||||
|
||||
#ifdef ANDROID
|
||||
static const char *log_end = "";
|
||||
# include <android/log.h>
|
||||
# define QUIT_FUNCTION(x) exit(x)
|
||||
# define _LOG_CMD(str) __android_log_print(ANDROID_LOG_ERROR, "apple2ix", "%s", str)
|
||||
#else
|
||||
extern FILE *error_log;
|
||||
static const char *log_end = "\n";
|
||||
# define QUIT_FUNCTION(x) exit(x)
|
||||
# define _LOG_CMD(str) \
|
||||
do { \
|
||||
if (UNLIKELY(!error_log)) { \
|
||||
error_log = stderr; \
|
||||
} \
|
||||
fprintf(error_log, "%s", str); \
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
#define _MYFILE_ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
#define _LOG(...) \
|
||||
do { \
|
||||
int _err = errno; \
|
||||
errno = 0; \
|
||||
\
|
||||
char *syserr_str = NULL; \
|
||||
char *glerr_str = NULL; \
|
||||
if (_err) { \
|
||||
asprintf(&syserr_str, " (syserr:%s)", strerror(_err)); \
|
||||
} \
|
||||
if (_glerr) { \
|
||||
asprintf(&glerr_str, " (glerr:%04X)", _glerr); \
|
||||
} \
|
||||
\
|
||||
char *buf0 = NULL; \
|
||||
asprintf(&buf0, __VA_ARGS__); \
|
||||
\
|
||||
char *buf = NULL; \
|
||||
asprintf(&buf, "%s:%d (%s) -%s%s %s%s", _MYFILE_, __LINE__, __func__, syserr_str ? : "", glerr_str ? : "", buf0, log_end); \
|
||||
\
|
||||
_LOG_CMD(buf); \
|
||||
\
|
||||
free(buf0); \
|
||||
free(buf); \
|
||||
if (syserr_str) { \
|
||||
free(syserr_str); \
|
||||
} \
|
||||
if (glerr_str) { \
|
||||
free(glerr_str); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if !defined(NDEBUG) || (defined(NDEBUG) && defined(ANDROID))
|
||||
|
||||
#ifdef ANDROID
|
||||
// Apparently some non-conformant Android devices (ahem, Spamsung, ahem) do not actually let me see what the assert
|
||||
// actually was before aborting/segfaulting ...
|
||||
# undef assert
|
||||
# define assert(e) \
|
||||
do { \
|
||||
if ((e)) { \
|
||||
/* ... */ \
|
||||
} else { \
|
||||
LOG( "!!! ASSERT !!! : " #e ); \
|
||||
sleep(1); \
|
||||
__assert2(_MYFILE_, __LINE__, __func__, #e); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define LOG(...) \
|
||||
if (do_logging) { \
|
||||
GLenum _glerr = safeGLGetError(); \
|
||||
_LOG(__VA_ARGS__); \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
} //
|
||||
|
||||
// GL_MAYBELOG() only logs if an OpenGL error occurred
|
||||
#define GL_MAYBELOG(...) \
|
||||
if (do_logging) { \
|
||||
GLenum _glerr = 0; \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
} //
|
||||
|
||||
#define ERRQUIT(...) \
|
||||
do { \
|
||||
GLenum _glerr = safeGLGetError(); \
|
||||
_LOG(__VA_ARGS__); \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
QUIT_FUNCTION(1); \
|
||||
} while (0)
|
||||
|
||||
// GL_ERRQUIT() only logs/quits if an OpenGL error occurred
|
||||
#define GL_ERRQUIT(...) \
|
||||
do { \
|
||||
GLenum _glerr = 0; \
|
||||
GLenum _last_glerr = 0; \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_last_glerr = _glerr; \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
if (_last_glerr) { \
|
||||
QUIT_FUNCTION(_last_glerr); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else // NDEBUG
|
||||
|
||||
#define LOG(...) \
|
||||
do { } while (0)
|
||||
|
||||
#define GL_MAYBELOG(...) \
|
||||
do { } while (0)
|
||||
|
||||
#define ERRQUIT(...) \
|
||||
do { } while (0)
|
||||
|
||||
#define GL_ERRQUIT(...) \
|
||||
do { } while (0)
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
// memory management
|
||||
#include "memmngt.h"
|
||||
|
||||
|
140
src/meta/log.c
Normal file
140
src/meta/log.c
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2017 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
// log.c :
|
||||
// - simple and not-particularly-performant logging functions
|
||||
// - do not call in a tight loop!
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
# include <android/log.h>
|
||||
#endif
|
||||
|
||||
#define LOG_PATH_TEMPLATE "%s%sapple2ix_log.%u.txt"
|
||||
|
||||
bool do_logging = true;
|
||||
bool do_std_logging = true;
|
||||
|
||||
static int logFd = -1;
|
||||
static int logSiz = 0;
|
||||
static const unsigned int logRotateSize = 1024 * 1024;
|
||||
static const unsigned int logRotateCount = 4;
|
||||
|
||||
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void _log_stopLogging(void) {
|
||||
if (logFd >= 0) {
|
||||
TEMP_FAILURE_RETRY(fsync(logFd));
|
||||
TEMP_FAILURE_RETRY(close(logFd));
|
||||
logFd = -1;
|
||||
logSiz = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void _log_rotate(bool performRotation) {
|
||||
|
||||
_log_stopLogging();
|
||||
|
||||
int xflag = 0;
|
||||
if (LIKELY(performRotation)) {
|
||||
xflag = O_TRUNC;
|
||||
for (unsigned int i = logRotateCount; i>0; i--) {
|
||||
char *logPath0 = NULL;
|
||||
char *logPath1 = NULL;
|
||||
|
||||
ASPRINTF(&logPath0, LOG_PATH_TEMPLATE, data_dir, PATH_SEPARATOR, (i-1));
|
||||
ASPRINTF(&logPath1, LOG_PATH_TEMPLATE, data_dir, PATH_SEPARATOR, i);
|
||||
assert(logPath0);
|
||||
assert(logPath1);
|
||||
|
||||
int ret = -1;
|
||||
TEMP_FAILURE_RETRY(ret = rename(logPath0, logPath1));
|
||||
|
||||
FREE(logPath0);
|
||||
FREE(logPath1);
|
||||
}
|
||||
}
|
||||
|
||||
char *logPath = NULL;
|
||||
ASPRINTF(&logPath, LOG_PATH_TEMPLATE, data_dir, PATH_SEPARATOR, 0);
|
||||
assert(logPath);
|
||||
|
||||
TEMP_FAILURE_RETRY(logFd = open(logPath, O_WRONLY|O_CREAT|xflag, S_IRUSR|S_IWUSR));
|
||||
|
||||
logSiz = lseek(logFd, 0L, SEEK_END);
|
||||
|
||||
log_outputString("-------------------------------------------------------------------------------");
|
||||
|
||||
FREE(logPath);
|
||||
}
|
||||
|
||||
void log_init(void) {
|
||||
_log_rotate(/*performRotation:*/false);
|
||||
}
|
||||
|
||||
void log_outputString(const char * const str) {
|
||||
if (UNLIKELY(!str)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (UNLIKELY(!do_logging)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (do_std_logging) {
|
||||
#if defined(__ANDROID__) && !defined(NDEBUG)
|
||||
__android_log_print(ANDROID_LOG_ERROR, "apple2ix", "%s", str);
|
||||
#else
|
||||
fprintf(stderr, "%s\n", str);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (UNLIKELY(logFd < 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&log_mutex);
|
||||
|
||||
int expected_bytescount = strlen(str);
|
||||
int bytescount = 0;
|
||||
|
||||
do {
|
||||
ssize_t byteswritten = 0;
|
||||
TEMP_FAILURE_RETRY(byteswritten = write(logFd, str+bytescount, expected_bytescount-bytescount));
|
||||
if (UNLIKELY(byteswritten <= 0)) {
|
||||
break; // OOPS !
|
||||
}
|
||||
|
||||
bytescount += byteswritten;
|
||||
if (bytescount >= expected_bytescount) {
|
||||
bytescount = expected_bytescount;
|
||||
TEMP_FAILURE_RETRY(write(logFd, "\n", 1));
|
||||
TEMP_FAILURE_RETRY(fsync(logFd));
|
||||
logSiz += bytescount + 1;
|
||||
if (UNLIKELY(logSiz >= logRotateSize)) {
|
||||
_log_rotate(/*performRotation:*/true);
|
||||
}
|
||||
|
||||
break; // OKAY
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (UNLIKELY(bytescount != expected_bytescount)) {
|
||||
// logging is b0rked, shut it down ...
|
||||
_log_stopLogging();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&log_mutex);
|
||||
}
|
||||
|
141
src/meta/log.h
Normal file
141
src/meta/log.h
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2017 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H_
|
||||
#define _LOG_H_
|
||||
|
||||
#if VIDEO_OPENGL
|
||||
# include "video_util/glUtil.h"
|
||||
|
||||
// 2015/04/01 ... early calls to glGetError()--before a context exists--causes segfaults on MacOS X
|
||||
extern bool safe_to_do_opengl_logging;
|
||||
static inline GLenum safeGLGetError(void) {
|
||||
if (safe_to_do_opengl_logging && video_isRenderThread()) {
|
||||
return glGetError();
|
||||
}
|
||||
return (GLenum)0;
|
||||
}
|
||||
|
||||
#else
|
||||
# define GLenum int
|
||||
# define safeGLGetError() 0
|
||||
# define glGetError() 0
|
||||
#endif
|
||||
|
||||
// global logging kill switch
|
||||
extern bool do_logging;
|
||||
|
||||
// log to the standard log facility (e.g., stderr)
|
||||
extern bool do_std_logging;
|
||||
|
||||
// initialize logging facility
|
||||
void log_init(void);
|
||||
|
||||
// print a string to the log file. Terminating '\n' is added.
|
||||
void log_outputString(const char * const str);
|
||||
|
||||
#define _MYFILE_ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
#define _LOG(...) \
|
||||
do { \
|
||||
int _err = errno; \
|
||||
errno = 0; \
|
||||
\
|
||||
char *syserr_str = NULL; \
|
||||
char *glerr_str = NULL; \
|
||||
if (_err) { \
|
||||
asprintf(&syserr_str, " (syserr:%s)", strerror(_err)); \
|
||||
} \
|
||||
if (_glerr) { \
|
||||
asprintf(&glerr_str, " (glerr:%04X)", _glerr); \
|
||||
} \
|
||||
\
|
||||
char *buf0 = NULL; \
|
||||
asprintf(&buf0, __VA_ARGS__); \
|
||||
\
|
||||
char *buf = NULL; \
|
||||
asprintf(&buf, "%s:%d (%s) -%s%s %s", _MYFILE_, __LINE__, __func__, (syserr_str ? : ""), (glerr_str ? : ""), buf0); \
|
||||
\
|
||||
log_outputString(buf); \
|
||||
\
|
||||
free(buf0); \
|
||||
free(buf); \
|
||||
if (syserr_str) { \
|
||||
free(syserr_str); \
|
||||
} \
|
||||
if (glerr_str) { \
|
||||
free(glerr_str); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
// Apparently some non-conformant Android devices (ahem, Spamsung, ahem) do not actually let me see what the assert
|
||||
// actually was before aborting/segfaulting ...
|
||||
# undef assert
|
||||
# define assert(e) \
|
||||
do { \
|
||||
if ((e)) { \
|
||||
/* ... */ \
|
||||
} else { \
|
||||
LOG( "!!! ASSERT !!! : " #e ); \
|
||||
sleep(1); \
|
||||
__assert2(_MYFILE_, __LINE__, __func__, #e); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define LOG(...) \
|
||||
if (LIKELY(do_logging)) { \
|
||||
GLenum _glerr = safeGLGetError(); \
|
||||
_LOG(__VA_ARGS__); \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
} //
|
||||
|
||||
// GL_MAYBELOG() only logs if an OpenGL error occurred
|
||||
#define GL_MAYBELOG(...) \
|
||||
if (LIKELY(do_logging)) { \
|
||||
GLenum _glerr = 0; \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
} //
|
||||
|
||||
#define QUIT_FUNCTION(x) exit(x)
|
||||
|
||||
#define ERRQUIT(...) \
|
||||
do { \
|
||||
GLenum _glerr = safeGLGetError(); \
|
||||
_LOG(__VA_ARGS__); \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
QUIT_FUNCTION(1); \
|
||||
} while (0)
|
||||
|
||||
// GL_ERRQUIT() only logs/quits if an OpenGL error occurred
|
||||
#define GL_ERRQUIT(...) \
|
||||
do { \
|
||||
GLenum _glerr = 0; \
|
||||
GLenum _last_glerr = 0; \
|
||||
while ( (_glerr = safeGLGetError()) ) { \
|
||||
_last_glerr = _glerr; \
|
||||
_LOG(__VA_ARGS__); \
|
||||
} \
|
||||
if (_last_glerr) { \
|
||||
QUIT_FUNCTION(_last_glerr); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif // whole file
|
@ -29,8 +29,6 @@ typedef struct module_ctor_node_s {
|
||||
static module_ctor_node_s *head = NULL;
|
||||
static bool emulatorShuttingDown = false;
|
||||
|
||||
bool do_logging = true; // also controlled by NDEBUG
|
||||
FILE *error_log = NULL;
|
||||
const char *data_dir = NULL;
|
||||
char **argv = NULL;
|
||||
int argc = 0;
|
||||
@ -38,8 +36,9 @@ CrashHandler_s *crashHandler = NULL;
|
||||
|
||||
#if defined(CONFIG_DATADIR)
|
||||
static void _init_common(void) {
|
||||
LOG("Initializing common...");
|
||||
data_dir = STRDUP(CONFIG_DATADIR PATH_SEPARATOR PACKAGE_NAME);
|
||||
log_init();
|
||||
LOG("Initializing common...");
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void __init_common(void) {
|
||||
|
@ -45,7 +45,7 @@ void test_common_init(void) {
|
||||
#if __ANDROID__
|
||||
// tags help us wade through log soup
|
||||
#else
|
||||
do_logging = false;// silence regular emulator logging
|
||||
do_std_logging = false;// silence regular emulator logging
|
||||
#endif
|
||||
|
||||
extern void emulator_ctors(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user