X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=common%2Fos_posix.cpp;h=5d6bffe5dcdab406a23624692b965e1d0730305b;hb=0b5b75e507df681260ea9c43b142ee48fff780c5;hp=9271e8863b14c4f837ba9f131da41ca7f57d0f91;hpb=b4a3d1495a5e92ba23bf463bcea34a6e75b55294;p=apitrace diff --git a/common/os_posix.cpp b/common/os_posix.cpp index 9271e88..5d6bffe 100644 --- a/common/os_posix.cpp +++ b/common/os_posix.cpp @@ -23,6 +23,7 @@ * **************************************************************************/ +#ifndef _WIN32 #include #include @@ -30,112 +31,184 @@ #include #include -#include -#include +#include #include #include #include +#if defined(__linux__) +#include // PATH_MAX +#endif + #ifdef __APPLE__ +#include // PATH_MAX #include #endif -#include "os.hpp" - - -namespace os { - - -static pthread_mutex_t -mutex = PTHREAD_MUTEX_INITIALIZER; +#ifdef ANDROID +#include +#endif +#ifndef PATH_MAX +#warning PATH_MAX undefined +#define PATH_MAX 4096 +#endif -void -AcquireMutex(void) -{ - pthread_mutex_lock(&mutex); -} +#include "os.hpp" +#include "os_string.hpp" +#include "os_backtrace.hpp" -void -ReleaseMutex(void) -{ - pthread_mutex_unlock(&mutex); -} +namespace os { -bool -GetProcessName(char *str, size_t size) +String +getProcessName(void) { - char szProcessPath[PATH_MAX + 1]; - char *lpProcessName; + String path; + size_t size = PATH_MAX; + char *buf = path.buf(size); // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe #ifdef __APPLE__ - uint32_t len = sizeof szProcessPath; - if (_NSGetExecutablePath(szProcessPath, &len) != 0) { - *str = 0; - return false; + uint32_t len = size; + if (_NSGetExecutablePath(buf, &len) != 0) { + // grow buf and retry + buf = path.buf(len); + _NSGetExecutablePath(buf, &len); } + len = strlen(buf); #else ssize_t len; - len = readlink("/proc/self/exe", szProcessPath, sizeof(szProcessPath) - 1); - if (len == -1) { + len = readlink("/proc/self/exe", buf, size - 1); + if (len <= 0) { // /proc/self/exe is not available on setuid processes, so fallback to // /proc/self/cmdline. int fd = open("/proc/self/cmdline", O_RDONLY); if (fd >= 0) { - len = read(fd, szProcessPath, sizeof(szProcessPath) - 1); + // buf already includes trailing zero + len = read(fd, buf, size); close(fd); + if (len >= 0) { + len = strlen(buf); + } } } if (len <= 0) { - snprintf(str, size, "%i", (int)getpid()); - return true; + // fallback to process ID + len = snprintf(buf, size, "%i", (int)getpid()); + if (len >= size) { + len = size - 1; + } } #endif - szProcessPath[len] = 0; + path.truncate(len); - lpProcessName = strrchr(szProcessPath, '/'); - lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath; + return path; +} - strncpy(str, lpProcessName, size); - if (size) - str[size - 1] = 0; +String +getCurrentDir(void) +{ + String path; + size_t size = PATH_MAX; + char *buf = path.buf(size); + + getcwd(buf, size); + buf[size - 1] = 0; + + path.truncate(); + return path; +} - return true; +bool +createDirectory(const String &path) +{ + return mkdir(path, 0777) == 0; } bool -GetCurrentDir(char *str, size_t size) +String::exists(void) const { - char *ret; - ret = getcwd(str, size); - str[size - 1] = 0; - return ret ? true : false; + struct stat st; + int err; + + err = stat(str(), &st); + if (err) { + return false; + } + + return true; +} + +int execute(char * const * args) +{ + pid_t pid = fork(); + if (pid == 0) { + // child + execvp(args[0], args); + fprintf(stderr, "error: failed to execute:"); + for (unsigned i = 0; args[i]; ++i) { + fprintf(stderr, " %s", args[i]); + } + fprintf(stderr, "\n"); + exit(-1); + } else { + // parent + if (pid == -1) { + fprintf(stderr, "error: failed to fork\n"); + return -1; + } + int status = -1; + int ret; + waitpid(pid, &status, 0); + if (WIFEXITED(status)) { + ret = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + // match shell return code + ret = WTERMSIG(status) + 128; + } else { + ret = 128; + } + return ret; + } } +static volatile bool logging = false; + void -DebugMessage(const char *format, ...) +log(const char *format, ...) { + logging = true; va_list ap; va_start(ap, format); fflush(stdout); - vfprintf(stderr, format, ap); +#ifdef ANDROID + __android_log_vprint(ANDROID_LOG_DEBUG, "apitrace", format, ap); +#else + static FILE *log = NULL; + if (!log) { + // Duplicate stderr file descriptor, to prevent applications from + // redirecting our debug messages to somewhere else. + // + // Another alternative would be to log to /dev/tty when available. + log = fdopen(dup(STDERR_FILENO), "at"); + } + vfprintf(log, format, ap); + fflush(log); +#endif va_end(ap); + logging = false; } -long long GetTime(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_usec + tv.tv_sec*1000000LL; -} +#if defined(__APPLE__) +long long timeFrequency = 0LL; +#endif void -Abort(void) +abort(void) { - exit(0); + _exit(1); } @@ -151,26 +224,37 @@ struct sigaction old_actions[NUM_SIGNALS]; * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup */ -static void signal_handler(int sig, siginfo_t *info, void *context) +static void +signalHandler(int sig, siginfo_t *info, void *context) { + /* + * There are several signals that can happen when logging to stdout/stderr. + * For example, SIGPIPE will be emitted if stderr is a pipe with no + * readers. Therefore ignore any signal while logging by returning + * immediately, to prevent deadlocks. + */ + if (logging) { + return; + } + static int recursion_count = 0; - fprintf(stderr, "signal_handler: sig = %i\n", sig); + log("apitrace: warning: caught signal %i\n", sig); if (recursion_count) { - fprintf(stderr, "recursion with sig %i\n", sig); + log("apitrace: warning: recursion handling signal %i\n", sig); } else { - if (gCallback) { - ++recursion_count; + ++recursion_count; + if (gCallback) gCallback(); - --recursion_count; - } + os::dump_backtrace(); + --recursion_count; } struct sigaction *old_action; if (sig >= NUM_SIGNALS) { /* This should never happen */ - fprintf(stderr, "Unexpected signal %i\n", sig); + log("error: unexpected signal %i\n", sig); raise(SIGKILL); } old_action = &old_actions[sig]; @@ -180,7 +264,7 @@ static void signal_handler(int sig, siginfo_t *info, void *context) old_action->sa_sigaction(sig, info, context); } else { if (old_action->sa_handler == SIG_DFL) { - fprintf(stderr, "taking default action for signal %i\n", sig); + log("apitrace: info: taking default action for signal %i\n", sig); #if 1 struct sigaction dfl_action; @@ -203,34 +287,50 @@ static void signal_handler(int sig, siginfo_t *info, void *context) } void -SetExceptionCallback(void (*callback)(void)) +setExceptionCallback(void (*callback)(void)) { assert(!gCallback); if (!gCallback) { gCallback = callback; struct sigaction new_action; - new_action.sa_sigaction = signal_handler; + new_action.sa_sigaction = signalHandler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = SA_SIGINFO | SA_RESTART; for (int sig = 1; sig < NUM_SIGNALS; ++sig) { - // SIGKILL and SIGSTOP can't be handled - if (sig != SIGKILL && sig != SIGSTOP) { - if (sigaction(sig, NULL, &old_actions[sig]) >= 0) { - sigaction(sig, &new_action, NULL); - } + // SIGKILL and SIGSTOP can't be handled. + if (sig == SIGKILL || sig == SIGSTOP) { + continue; + } + + /* + * SIGPIPE can be emitted when writing to stderr that is redirected + * to a pipe without readers. It is also very unlikely to ocurr + * inside graphics APIs, and most applications where it can occur + * normally already ignore it. In summary, it is unlikely that a + * SIGPIPE will cause abnormal termination, which it is likely that + * intercepting here will cause problems, so simple don't intercept + * it here. + */ + if (sig == SIGPIPE) { + continue; + } + + if (sigaction(sig, NULL, &old_actions[sig]) >= 0) { + sigaction(sig, &new_action, NULL); } } } } void -ResetExceptionCallback(void) +resetExceptionCallback(void) { gCallback = NULL; } } /* namespace os */ +#endif // !defined(_WIN32)