EAPI Eina_Stringshare * eina_stringshare_add_length(const char *str, unsigned int slen) { if (!str) return NULL; else if (slen == 0) { eina_share_common_population_add(stringshare_share, slen); return ""; } else if (slen == 1) { eina_share_common_population_add(stringshare_share, slen); return (Eina_Stringshare *) _eina_stringshare_single + ((*str) << 1); } else if (slen < 4) { const char *s; eina_share_common_population_add(stringshare_share, slen); eina_spinlock_take(&_mutex_small); s = _eina_stringshare_small_add(str, slen); eina_spinlock_release(&_mutex_small); return s; } return eina_share_common_add_length(stringshare_share, str, slen * sizeof(char), sizeof(char)); }
static void _eio_pool_free(Eio_Alloc_Pool *pool, void *data) { if (pool->count >= EIO_PROGRESS_LIMIT) { eina_spinlock_take(&memory_pool_lock); memory_pool_usage -= pool->mem_size; eina_spinlock_release(&memory_pool_lock); free(data); if (memory_pool_limit > 0 && memory_pool_usage < memory_pool_limit) { eina_lock_take(&(memory_pool_mutex)); if (memory_pool_suspended) eina_condition_broadcast(&(memory_pool_cond)); eina_lock_release(&(memory_pool_mutex)); } } else { eina_lock_take(&(pool->lock)); eina_trash_push(&pool->trash, data); pool->count++; eina_lock_release(&(pool->lock)); } }
EAPI void eina_evlog_stop(void) { eina_spinlock_take(&_evlog_lock); _evlog_go--; if (_evlog_go == 0) { free_buf(&(buffers[0])); free_buf(&(buffers[1])); } eina_spinlock_release(&_evlog_lock); }
EAPI void eina_evlog_start(void) { eina_spinlock_take(&_evlog_lock); _evlog_go++; if (_evlog_go == 1) { // alloc 2 buffers for spinning around in alloc_buf(&(buffers[0]), EVLOG_BUF_SIZE); alloc_buf(&(buffers[1]), EVLOG_BUF_SIZE); } eina_spinlock_release(&_evlog_lock); }
EAPI void eina_evlog(const char *event, void *obj, double srctime, const char *detail) { Eina_Evlog_Item *item; int size; char *strings; double now = get_time(); unsigned short detail_offset = 0; unsigned short event_size; eina_spinlock_take(&_evlog_lock); if (!_evlog_go) { eina_spinlock_release(&_evlog_lock); return; } size = sizeof(Eina_Evlog_Item); event_size = strlen(event) + 1; size += event_size; if (detail) { detail_offset = size; size += strlen(detail) + 1; } size = sizeof(double) * ((size + sizeof(double) - 1) / sizeof(double)); strings = push_buf(buf, size); item = (Eina_Evlog_Item *)strings; item->tim = now; item->srctim = srctime; item->thread = (unsigned long long)pthread_self(); item->obj = (unsigned long long)obj; item->event_offset = sizeof(Eina_Evlog_Item); item->detail_offset = detail_offset; item->event_next = size; strcpy(strings + sizeof(Eina_Evlog_Item), event); if (detail_offset > 0) strcpy(strings + detail_offset, detail); eina_spinlock_release(&_evlog_lock); }
EAPI Eina_Stringshare * eina_stringshare_ref(Eina_Stringshare *str) { int slen; if (!str) return NULL; /* special cases */ if (str[0] == '\0') slen = 0; else if (str[1] == '\0') slen = 1; else if (str[2] == '\0') slen = 2; else if (str[3] == '\0') slen = 3; else slen = 3 + (int)strlen(str + 3); if (slen < 2) { eina_share_common_population_add(stringshare_share, slen); return str; } else if (slen < 4) { const char *s; eina_share_common_population_add(stringshare_share, slen); eina_spinlock_take(&_mutex_small); s = _eina_stringshare_small_add(str, slen); eina_spinlock_release(&_mutex_small); return s; } return eina_share_common_ref(stringshare_share, str); }
static void * _eio_pool_malloc(Eio_Alloc_Pool *pool) { void *result = NULL; if (pool->count) { eina_lock_take(&(pool->lock)); result = eina_trash_pop(&pool->trash); if (result) pool->count--; eina_lock_release(&(pool->lock)); } if (!result) { result = malloc(pool->mem_size); eina_spinlock_take(&memory_pool_lock); if (result) memory_pool_usage += pool->mem_size; eina_spinlock_release(&memory_pool_lock); } return result; }
EAPI void eina_stringshare_del(Eina_Stringshare *str) { int slen; if (!str) return; /* special cases */ if (str[0] == '\0') slen = 0; else if (str[1] == '\0') slen = 1; else if (str[2] == '\0') slen = 2; else if (str[3] == '\0') slen = 3; else slen = 4; /* handled later */ if (slen < 2) { eina_share_common_population_del(stringshare_share, slen); return; } else if (slen < 4) { eina_share_common_population_del(stringshare_share, slen); eina_spinlock_take(&_mutex_small); _eina_stringshare_small_del(str, slen); eina_spinlock_release(&_mutex_small); return; } if (!eina_share_common_del(stringshare_share, str)) CRI("EEEK trying to del non-shared stringshare \"%s\"", str); }
EAPI Eina_Evlog_Buf * eina_evlog_steal(void) { Eina_Evlog_Buf *stolen = NULL; eina_spinlock_take(&_evlog_lock); if (buf == &(buffers[0])) { buf = &(buffers[1]); buf->top = 0; buf->overflow = 0; stolen = &(buffers[0]); } else { buf = &(buffers[0]); buf->top = 0; buf->overflow = 0; stolen = &(buffers[1]); } eina_spinlock_release(&_evlog_lock); return stolen; }
// remove a thread id from our tracking array - simply find and shuffle all // later elements down. this array should be small almsot all the time and // shouldn't bew changing THAT often for this to matter void _eina_debug_thread_del(void *th) { pthread_t *pth = th; int i; // take a thread tracking lock eina_spinlock_take(&_eina_debug_thread_lock); // find the thread id to remove for (i = 0; i < _eina_debug_thread_active_num; i++) { if (_eina_debug_thread_active[i] == *pth) { // found it - now shuffle down all further thread id's in array for (; i < (_eina_debug_thread_active_num - 1); i++) _eina_debug_thread_active[i] = _eina_debug_thread_active[i + 1]; // reduce our counter and get out of loop _eina_debug_thread_active_num--; break; } } // release lock cleanly eina_spinlock_release(&_eina_debug_thread_lock); }
// add a thread id to our tracking array - very simple. add to end, and // if array to small, reallocate it to be bigger by 16 slots AND double that // size (so grows should slow down FAST). we will never shrink this array void _eina_debug_thread_add(void *th) { pthread_t *pth = th; // take thread tracking lock eina_spinlock_take(&_eina_debug_thread_lock); // if we don't have enough space to store thread id's - make some more if (_thread_active_size < (_eina_debug_thread_active_num + 1)) { pthread_t *threads = realloc (_eina_debug_thread_active, ((_eina_debug_thread_active_num + 16) * 2) * sizeof(pthread_t *)); if (threads) { _eina_debug_thread_active = threads; _thread_active_size = (_eina_debug_thread_active_num + 16) * 2; } } // add new thread id to the end _eina_debug_thread_active[_eina_debug_thread_active_num] = *pth; _eina_debug_thread_active_num++; // release our lock cleanly eina_spinlock_release(&_eina_debug_thread_lock); }
static inline void _config_lock(Email_Config *cfg) { eina_spinlock_take(&cfg->lock); }
// do a "fast lookup" of a filename to a file path for debug output. this // relies on caching to avoid system calls and assumes that once we know // the full path of a given filename, we can know its full path reliably. // if we can't we'd be in trouble anyway as the filename and path lookup // failure is due maybe to a deleted file or renamed file and then we are // going to have a bad day either way. const char * _eina_debug_file_get(const char *fname) { char buf[4096]; const char *file; static const char **path = NULL; static char *pathstrs = NULL; // no filename provided if ((!fname) || (!fname[0])) return NULL; // it's a full path so return as-is if (fname[0] == '/') return fname; // first look in cache for filename -> full path lookup and if // there, return that (yes - assuming filesystem paths doesn't change // which is unlikely as they were set up at star most likely) eina_spinlock_take(&_eina_debug_lock); file = _eina_debug_file_lookup(fname); eina_spinlock_release(&_eina_debug_lock); if (file) return file; // store PATH permanently - yes. if it changes runtime it will break. // for speed reasons we need to assume it won't change. store path broken // down into an array of ptrs to strings with NULL ptr at the end. this // will only execute once as an "init" for a breoken up path so it should // not matter speed-wise eina_spinlock_take(&_eina_debug_lock); if (!path) { unsigned int n; char *p1, *p2; const char *p; const char *pathstr = getenv("PATH"); if (!pathstr) { eina_spinlock_release(&_eina_debug_lock); return NULL; } // dup the entire env as we will rpelace : with 0 bytes to break str pathstrs = _eina_debug_chunk_strdup(pathstr); for (n = 0, p = pathstr; *p;) { n++; p = strchr(p, ':'); if (!p) break; p++; } path = _eina_debug_chunk_push(sizeof(const char *) * (n + 1)); for (n = 0, p1 = pathstrs; *p1; n++) { path[n] = p1; p2 = strchr(p1, ':'); if (!p2) break; *p2 = 0; p1 = p2 + 1; } path[n] = NULL; } eina_spinlock_release(&_eina_debug_lock); // a relative path - resolve with realpath. due to the cache store above // we shouldn't have to do this very often if ((!strncmp(fname, "./", 2)) || (!strncmp(fname, "../", 3))) { // relative path if (realpath(fname, buf)) file = buf; else file = NULL; } // search in $PATH for the file then - this should also be very rare as // we will store and cache results permanently else if (path) { struct stat st; unsigned int n; for (n = 0; path[n]; n++) { snprintf(buf, sizeof(buf), "%s/%s", path[n], fname); if (stat(buf, &st) == 0) { file = buf; break; } } } // if it's found - store it in cache for later if (file) { eina_spinlock_take(&_eina_debug_lock); file = _eina_debug_file_store(fname, file); eina_spinlock_release(&_eina_debug_lock); } return file; }