/* EINA - EFL data type library * Copyright (C) 2015 Carsten Haitzler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; * if not, see . */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "Eina.h" #include "eina_evlog.h" #include "eina_debug.h" #ifdef EINA_HAVE_DEBUG # ifdef HAVE_MMAP # include # endif # define EVLOG_BUF_SIZE (4 * (1024 * 1024)) static Eina_Spinlock _evlog_lock; static int _evlog_go = 0; static Eina_Evlog_Buf *buf; // current event log we are writing events to static Eina_Evlog_Buf buffers[2]; // double-buffer our event log buffers static inline double get_time(void) { struct timeval timev; gettimeofday(&timev, NULL); return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000.0); } static void alloc_buf(Eina_Evlog_Buf *b, unsigned int size) { if (b->buf) return; b->size = size; b->top = 0; # ifdef HAVE_MMAP b->buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (b->buf == MAP_FAILED) b->buf = NULL; # else b->buf = malloc(size); # endif b->overflow = 0; } static void free_buf(Eina_Evlog_Buf *b) { if (!b->buf) return; b->size = 0; b->top = 0; # ifdef HAVE_MMAP munmap(b->buf, b->size); # else free(b->buf); # endif b->buf = NULL; } static inline void * push_buf(Eina_Evlog_Buf *b, unsigned int size) { void *ptr; if (b->size < size) abort(); if ((b->top + size) > (b->size)) { b->overflow++; b->top = 0; } ptr = (b->buf + b->top); b->top += size; return ptr; } 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_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; } 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_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); } Eina_Bool eina_evlog_init(void) { eina_spinlock_new(&_evlog_lock); buf = &(buffers[0]); eina_evlog("+eina_init", NULL, 0.0, NULL); return EINA_TRUE; } Eina_Bool eina_evlog_shutdown(void) { // yes - we don't free tyhe evlog buffers. they may be in used by debug th eina_spinlock_free(&_evlog_lock); return EINA_TRUE; } #else EAPI void eina_evlog(const char *event EINA_UNUSED, void *obj EINA_UNUSED, double srctime EINA_UNUSED, const char *detail EINA_UNUSED) { } EAPI Eina_Evlog_Buf * eina_evlog_steal(void) { return NULL; } EAPI void eina_evlog_start(void) { } EAPI void eina_evlog_stop(void) { } Eina_Bool eina_evlog_init(void) { return EINA_TRUE; } Eina_Bool eina_evlog_shutdown(void) { return EINA_TRUE; } #endif