//libroar.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2013 * * This file is part of libroar a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * NOTE for everyone want's to change something and send patches: * read README and HACKING! There a addition information on * the license of this document you need to read before you send * any patches. * * NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc * or libpulse*: * The libs libroaresd, libroararts and libroarpulse link this lib * and are therefore GPL. Because of this it may be illigal to use * them with any software that uses libesd, libartsc or libpulse*. */ /* ckport options: * ckport: ignore-symbol: sleep of target win32 -- checked by configure */ #include "libroar.h" #ifndef roar_mm_mlock int roar_mm_mlock(const void *addr, size_t len) { #if defined(ROAR_TARGET_WIN32) /* GlobalLock() generates errors. Maybe we do not use correctly. * We just ignore that at the moment and throw NOSYS. * * return GlobalLock(addr) == addr ? 0 : -1; */ roar_err_set(ROAR_ERROR_NOSYS); return -1; #elif defined(ROAR_TARGET_MICROCONTROLLER) return 0; #elif defined(_SC_PAGESIZE) long sz = sysconf(_SC_PAGESIZE); unsigned long int pos = (unsigned long int) addr; len += sz - (len % sz); pos -= pos % sz; return mlock((void*)pos, len); #else roar_err_set(ROAR_ERROR_NOSYS); return -1; #endif } #endif #ifndef roar_mm_munlock int roar_mm_munlock(const void *addr, size_t len) { #if defined(ROAR_TARGET_WIN32) // TODO: find out what do do here. GlobalUnLock()? does such a function exist? // return GlobalLock(addr) == addr ? 0 : -1; roar_err_set(ROAR_ERROR_NOSYS); return -1; #elif defined(ROAR_TARGET_MICROCONTROLLER) return 0; #elif defined(_SC_PAGESIZE) long sz = sysconf(_SC_PAGESIZE); unsigned long int pos = (unsigned long int) addr; len += sz - (len % sz); pos -= pos % sz; return munlock((void*)pos, len); #else roar_err_set(ROAR_ERROR_NOSYS); return -1; #endif } #endif // for compatibility with old versions: int _ROAR_MLOCK(const void *addr, size_t len) { roar_debug_warn_obsolete("_ROAR_MLOCK", "roar_mm_mlock", NULL); return roar_mm_mlock(addr, len); } int roar_usleep(uint_least32_t t) { #ifdef ROAR_TARGET_WIN32 Sleep(t/(uint_least32_t)1000); return 0; #elif defined(ROAR_HAVE_NANOSLEEP) struct timespec tv; struct timespec left; if ( t >= (uint_least32_t)1000000 ) { tv.tv_sec = t/(uint_least32_t)1000000; t -= tv.tv_sec*(uint_least32_t)1000000; } else { tv.tv_sec = 0; } tv.tv_nsec = t*(uint_least32_t)1000; while (nanosleep(&tv, &left) == -1) memcpy(&tv, &left, sizeof(tv)); return 0; #elif defined(ROAR_HAVE_USLEEP) usleep(t); return 0; #else ROAR_ERR("roar_usleep(t=%" LIBROAR__ll "u): can not sleep: not implemented", (LIBROAR__longlong unsigned int)t); roar_strap(ROAR_TRAP_GROUP_LIBROAR, "usleep.not-implemented"); roar_err_set(ROAR_ERROR_NOSYS); return -1; #endif } int roar_sleep(int t) { if ( t < 0 ) { roar_err_set(ROAR_ERROR_CAUSALITY); return -1; } #ifdef ROAR_TARGET_WIN32 Sleep(1000L*(long)t); #elif defined(ROAR_HAVE_SLEEP) while (t) t = sleep(t); #else while (t) { if ( roar_usleep(500000) == -1 ) return -1; if ( roar_usleep(500000) == -1 ) return -1; t--; } #endif return 0; } static pid_t _libroar_fork(void ** context, void * userdata) { #ifdef ROAR_HAVE_FORK pid_t ret; (void)context, (void)userdata; ret = fork(); if ( ret == -1 ) roar_err_from_errno(); return ret; #else roar_err_set(ROAR_ERROR_NOSYS); return (pid_t)-1; #endif } static const struct roar_libroar_forkapi _libroar_forkapi = { .prefork = NULL, .fork = _libroar_fork, .failed = NULL, .parent = NULL, .child = NULL, .userdata = NULL }; pid_t roar_fork(const struct roar_libroar_forkapi * api) { void * context = NULL; int err; pid_t ret; if ( api == NULL ) api = &_libroar_forkapi; if ( api->fork == NULL ) { roar_err_set(ROAR_ERROR_INVAL); return -1; } if ( api->prefork != NULL ) { if ( api->prefork(&context, api->userdata) != 0 ) { if ( api->failed != NULL ) api->failed(&context, api->userdata); if ( context != NULL ) { err = roar_error; roar_mm_free(context); roar_error = err; } return (pid_t)-1; } } if ( (ret = api->fork(&context, api->userdata)) == (pid_t)-1 ) { if ( api->failed != NULL ) api->failed(&context, api->userdata); if ( context != NULL ) { err = roar_error; roar_mm_free(context); roar_error = err; } return (pid_t)-1; } if ( ret == (pid_t)0 ) { if ( api->child != NULL ) api->child(&context, api->userdata); } else { if ( api->parent != NULL ) api->parent(&context, api->userdata, ret); } if ( context != NULL ) { err = roar_error; roar_mm_free(context); roar_error = err; } return ret; } int roar_reset(enum roar_reset what) { char c; int i; enum roar_reset subsets = ROAR_RESET_NONE; roar_err_set(ROAR_ERROR_NONE); switch (what) { case ROAR_RESET_NONE: return 0; break; case ROAR_RESET_UNKNOWN: case ROAR_RESET_EOL: roar_err_set(ROAR_ERROR_INVAL); return -1; break; case ROAR_RESET_ON_FORK: subsets |= ROAR_RESET_MEMORY|ROAR_RESET_RANDOMPOOL; break; case ROAR_RESET_ON_EXIT: case ROAR_RESET_ON_PRE_EXEC: subsets |= ROAR_RESET_MEMORY|ROAR_RESET_CONFIG; break; default: if ( what & 0x80 ) { subsets |= what; } else { roar_err_set(ROAR_ERROR_INVAL); return -1; } break; } // strip 0x80 so we can easly test on the other bit per subsystem. what |= 0x80; what -= 0x80; if ( what & ROAR_RESET_MEMORY ) { (void)roar_mm_reset(); } if ( what & ROAR_RESET_CONFIG ) { roar_libroar_reset_config(); } if ( what & ROAR_RESET_RANDOMPOOL ) { for (i = 0; i < 16; i++) { roar_random_gen_nonce(&c, 1); roar_random_uint16(); roar_random_uint32(); } } roar_err_set(ROAR_ERROR_NONE); return 0; } void roar_panic_real(enum roar_fatal_error error, const char * info, unsigned long int line, const char * file, const char * prefix, const char * func) { const char * errname = NULL; //#define ROAR_ERR(format, args...) roar_debug_msg(ROAR_DEBUG_TYPE_ERROR, __LINE__, __FILE__, ROAR_DBG_PREFIX, format, ## args) // we do not support info-text at the moment. (void)info; if ( func == NULL ) func = ""; switch (error) { case ROAR_FATAL_ERROR_MEMORY_CORRUPTION_GUARD: roar_debug_msg(ROAR_DEBUG_TYPE_ERROR, line, file, prefix, "in %s() a guard segment memory corruption was detected. Backup your data and terminate this program. Report this lion to developer. Thanks.", func); return; break; case ROAR_FATAL_ERROR_UNKNOWN: errname = ""; break; case ROAR_FATAL_ERROR_MEMORY_CORRUPTION: errname = "Memory corruption"; break; case ROAR_FATAL_ERROR_CPU_FAILURE: errname = "CPU failure, replace hardware"; break; case ROAR_FATAL_ERROR_MEMORY_USED_AFTER_FREE: errname = "Memory used after free"; break; case ROAR_FATAL_ERROR_MEMORY_DOUBLE_FREE: errname = "Memory double freed"; break; case ROAR_FATAL_ERROR_WATCHDOG: errname = "Watchdog Timeout"; break; default: errname = ""; break; } roar_debug_msg(ROAR_DEBUG_TYPE_ERROR, line, file, prefix, "in %s() a _FATAL_ error of type \"%s\" was detected. Terminating program. Report this lion to developer. Thanks.", func, errname); #ifdef SIGKILL raise(SIGKILL); #endif abort(); #ifdef ROAR_HAVE_U_EXIT ROAR_U_EXIT(1); #endif while(1); } const char * roar_version_string(void) { return ROAR_VERSION_STRING; } uint32_t roar_version_num(void) { return _ROAR_MKVERSION(ROAR_VERSION_MAJOR, ROAR_VERSION_MINOR, ROAR_VERSION_REV); } //ll