util.c   util.c 
skipping to change at line 24 skipping to change at line 24
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with libqb. If not, see <http://www.gnu.org/licenses/>. * along with libqb. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "os_base.h" #include "os_base.h"
#include "util_int.h" #include "util_int.h"
#include <sys/shm.h>
#include <sys/mman.h>
#include <pthread.h> #include <pthread.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <qb/qbdefs.h> #include <qb/qbdefs.h>
#include <qb/qbutil.h> #include <qb/qbutil.h>
struct qb_thread_lock_s { struct qb_thread_lock_s {
qb_thread_lock_type_t type; qb_thread_lock_type_t type;
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK #ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
pthread_spinlock_t spinlock; pthread_spinlock_t spinlock;
#endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */ #endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */
pthread_mutex_t mutex; pthread_mutex_t mutex;
}; };
qb_thread_lock_t *qb_thread_lock_create(qb_thread_lock_type_t type) qb_thread_lock_t *
qb_thread_lock_create(qb_thread_lock_type_t type)
{ {
struct qb_thread_lock_s *tl = malloc(sizeof(struct qb_thread_lock_s) ); struct qb_thread_lock_s *tl = malloc(sizeof(struct qb_thread_lock_s) );
int32_t res; int32_t res;
if (tl == NULL) {
return NULL;
}
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK #ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
if (type == QB_THREAD_LOCK_SHORT) { if (type == QB_THREAD_LOCK_SHORT) {
tl->type = QB_THREAD_LOCK_SHORT; tl->type = QB_THREAD_LOCK_SHORT;
res = pthread_spin_init(&tl->spinlock, 1); res = pthread_spin_init(&tl->spinlock, 1);
} else } else
#endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */ #endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */
{ {
tl->type = QB_THREAD_LOCK_LONG; tl->type = QB_THREAD_LOCK_LONG;
res = pthread_mutex_init(&tl->mutex, NULL); res = pthread_mutex_init(&tl->mutex, NULL);
} }
if (res == 0) { if (res == 0) {
return tl; return tl;
} else { } else {
free(tl); free(tl);
return NULL; return NULL;
} }
} }
int32_t qb_thread_lock(qb_thread_lock_t * tl) int32_t
qb_thread_lock(qb_thread_lock_t * tl)
{ {
int32_t res; int32_t res;
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK #ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
if (tl->type == QB_THREAD_LOCK_SHORT) { if (tl->type == QB_THREAD_LOCK_SHORT) {
res = -pthread_spin_lock(&tl->spinlock); res = -pthread_spin_lock(&tl->spinlock);
} else } else
#endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */ #endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */
{ {
res = -pthread_mutex_lock(&tl->mutex); res = -pthread_mutex_lock(&tl->mutex);
} }
return res; return res;
} }
int32_t qb_thread_unlock(qb_thread_lock_t * tl) int32_t
qb_thread_unlock(qb_thread_lock_t * tl)
{ {
int32_t res; int32_t res;
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK #ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
if (tl->type == QB_THREAD_LOCK_SHORT) { if (tl->type == QB_THREAD_LOCK_SHORT) {
res = -pthread_spin_unlock(&tl->spinlock); res = -pthread_spin_unlock(&tl->spinlock);
} else } else
#endif #endif
{ {
res = -pthread_mutex_unlock(&tl->mutex); res = -pthread_mutex_unlock(&tl->mutex);
} }
return res; return res;
} }
int32_t qb_thread_trylock(qb_thread_lock_t * tl) int32_t
qb_thread_trylock(qb_thread_lock_t * tl)
{ {
int32_t res; int32_t res;
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK #ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
if (tl->type == QB_THREAD_LOCK_SHORT) { if (tl->type == QB_THREAD_LOCK_SHORT) {
res = -pthread_spin_trylock(&tl->spinlock); res = -pthread_spin_trylock(&tl->spinlock);
} else } else
#endif #endif
{ {
res = -pthread_mutex_trylock(&tl->mutex); res = -pthread_mutex_trylock(&tl->mutex);
} }
return res; return res;
} }
int32_t qb_thread_lock_destroy(qb_thread_lock_t * tl) int32_t
qb_thread_lock_destroy(qb_thread_lock_t * tl)
{ {
int32_t res; int32_t res;
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK #ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
if (tl->type == QB_THREAD_LOCK_SHORT) { if (tl->type == QB_THREAD_LOCK_SHORT) {
res = -pthread_spin_destroy(&tl->spinlock); res = -pthread_spin_destroy(&tl->spinlock);
} else } else
#endif #endif
{ {
res = -pthread_mutex_destroy(&tl->mutex); res = -pthread_mutex_destroy(&tl->mutex);
} }
free(tl); free(tl);
return res; return res;
} }
/* void
* --------------------------------------------------- qb_timespec_add_ms(struct timespec *ts, int32_t ms)
* Logging functions for the library.
*/
static qb_util_log_fn_t real_log_fn = NULL;
void _qb_util_log(const char *file_name,
int32_t file_line, int32_t severity, const char *format, .
..)
{
if (real_log_fn) {
va_list ap;
char msg[256];
va_start(ap, format);
vsnprintf(msg, 256, format, ap);
va_end(ap);
real_log_fn(file_name, file_line, severity, msg);
}
}
void qb_timespec_add_ms(struct timespec *ts, int32_t ms)
{ {
#ifndef S_SPLINT_S #ifndef S_SPLINT_S
ts->tv_sec = ms / 1000; ts->tv_sec = ms / 1000;
ts->tv_nsec = (ms % 1000) * QB_TIME_NS_IN_MSEC; ts->tv_nsec = (ms % 1000) * QB_TIME_NS_IN_MSEC;
if (ts->tv_nsec >= 1000000000L) { if (ts->tv_nsec >= 1000000000L) {
ts->tv_sec++; ts->tv_sec++;
ts->tv_nsec = ts->tv_nsec - 1000000000L; ts->tv_nsec = ts->tv_nsec - 1000000000L;
} }
#endif /* S_SPLINT_S */ #endif /* S_SPLINT_S */
} }
#ifdef HAVE_MONOTONIC_CLOCK #ifdef HAVE_MONOTONIC_CLOCK
uint64_t qb_util_nano_current_get(void) uint64_t
qb_util_nano_current_get(void)
{ {
uint64_t nano_monotonic; uint64_t nano_monotonic;
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
nano_monotonic = nano_monotonic =
(ts.tv_sec * QB_TIME_NS_IN_SEC) + (uint64_t)ts.tv_nsec; (ts.tv_sec * QB_TIME_NS_IN_SEC) + (uint64_t) ts.tv_nsec;
return (nano_monotonic); return (nano_monotonic);
} }
uint64_t qb_util_nano_from_epoch_get(void)
uint64_t
qb_util_nano_from_epoch_get(void)
{ {
uint64_t nano_monotonic; uint64_t nano_monotonic;
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
nano_monotonic = nano_monotonic =
(ts.tv_sec * QB_TIME_NS_IN_SEC) + (uint64_t)ts.tv_nsec; (ts.tv_sec * QB_TIME_NS_IN_SEC) + (uint64_t) ts.tv_nsec;
return (nano_monotonic); return (nano_monotonic);
} }
uint64_t qb_util_nano_monotonic_hz(void) uint64_t
qb_util_nano_monotonic_hz(void)
{ {
uint64_t nano_monotonic_hz; uint64_t nano_monotonic_hz;
struct timespec ts; struct timespec ts;
clock_getres(CLOCK_MONOTONIC, &ts); clock_getres(CLOCK_MONOTONIC, &ts);
nano_monotonic_hz = nano_monotonic_hz =
QB_TIME_NS_IN_SEC / ((ts.tv_sec * QB_TIME_NS_IN_SEC) + QB_TIME_NS_IN_SEC / ((ts.tv_sec * QB_TIME_NS_IN_SEC) + ts.tv_nse
ts.tv_nsec); c);
return (nano_monotonic_hz); return (nano_monotonic_hz);
} }
void qb_util_timespec_from_epoch_get(struct timespec *ts) void
qb_util_timespec_from_epoch_get(struct timespec *ts)
{ {
clock_gettime(CLOCK_REALTIME, ts); clock_gettime(CLOCK_REALTIME, ts);
} }
#else #else
uint64_t qb_util_nano_current_get(void) uint64_t
qb_util_nano_current_get(void)
{ {
return qb_util_nano_from_epoch_get(); return qb_util_nano_from_epoch_get();
} }
uint64_t qb_util_nano_monotonic_hz(void) uint64_t
qb_util_nano_monotonic_hz(void)
{ {
return HZ; return HZ;
} }
void qb_util_timespec_from_epoch_get(struct timespec *ts) void
qb_util_timespec_from_epoch_get(struct timespec *ts)
{ {
struct timeval time_from_epoch; struct timeval time_from_epoch;
gettimeofday(&time_from_epoch, 0); gettimeofday(&time_from_epoch, 0);
#ifndef S_SPLINT_S #ifndef S_SPLINT_S
ts->tv_sec = time_from_epoch.tv_sec; ts->tv_sec = time_from_epoch.tv_sec;
ts->tv_nsec = time_from_epoch.tv_usec * QB_TIME_NS_IN_USEC; ts->tv_nsec = time_from_epoch.tv_usec * QB_TIME_NS_IN_USEC;
#endif /* S_SPLINT_S */ #endif /* S_SPLINT_S */
} }
uint64_t qb_util_nano_from_epoch_get(void) uint64_t
qb_util_nano_from_epoch_get(void)
{ {
uint64_t nano_from_epoch; uint64_t nano_from_epoch;
struct timeval time_from_epoch; struct timeval time_from_epoch;
gettimeofday(&time_from_epoch, 0); gettimeofday(&time_from_epoch, 0);
nano_from_epoch = ((time_from_epoch.tv_sec * QB_TIME_NS_IN_SEC) + nano_from_epoch = ((time_from_epoch.tv_sec * QB_TIME_NS_IN_SEC) +
(time_from_epoch.tv_usec * QB_TIME_NS_IN_USEC)); (time_from_epoch.tv_usec * QB_TIME_NS_IN_USEC));
return (nano_from_epoch); return (nano_from_epoch);
} }
#endif #endif /* HAVE_MONOTONIC_CLOCK */
void qb_util_set_log_function(qb_util_log_fn_t fn) struct qb_util_stopwatch {
uint64_t started;
uint64_t stopped;
};
qb_util_stopwatch_t *
qb_util_stopwatch_create(void)
{ {
real_log_fn = fn; struct qb_util_stopwatch *sw;
sw = (struct qb_util_stopwatch *)calloc(1, sizeof(struct qb_util_sto
pwatch));
return sw;
} }
static int32_t open_mmap_file(char *path, uint32_t file_flags) void
qb_util_stopwatch_free(qb_util_stopwatch_t * sw)
{ {
if (strstr(path, "XXXXXX") != NULL) { free(sw);
return mkstemp(path);
}
return open(path, file_flags, 0600);
} }
/* void
* --------------------------------------------------- qb_util_stopwatch_start(qb_util_stopwatch_t * sw)
* shared memory functions.
*/
int32_t qb_util_mmap_file_open(char *path, const char *file, size_t bytes,
uint32_t file_flags)
{ {
int32_t fd; sw->started = qb_util_nano_current_get();
int32_t i; sw->stopped = 0;
int32_t res = 0;
ssize_t written;
char *buffer = NULL;
char *is_absolute = strchr(file, '/');;
if (is_absolute) {
strcpy(path, file);
} else {
snprintf(path, PATH_MAX, "/dev/shm/%s", file);
}
fd = open_mmap_file(path, file_flags);
if (fd < 0 && !is_absolute) {
res = -errno;
qb_util_log(LOG_ERR, "couldn't open file %s error: %s",
path, strerror(-res));
snprintf(path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
fd = open_mmap_file(path, file_flags);
if (fd < 0) {
res = -errno;
qb_util_log(LOG_ERR, "couldn't open file %s error: %
s",
path, strerror(-res));
return res;
}
}
if (ftruncate(fd, bytes) == -1) {
res = -errno;
qb_util_log(LOG_ERR,
"couldn't truncate file %s error: %s",
path, strerror(-res));
goto unlink_exit;
}
if (file_flags & O_CREAT) {
long page_size = sysconf(_SC_PAGESIZE);
buffer = calloc(1, page_size);
if (buffer == NULL) {
res = -ENOMEM;
goto unlink_exit;
}
for (i = 0; i < (bytes / page_size); i++) {
retry_write:
written = write (fd, buffer, page_size);
if (written == -1 && errno == EINTR) {
goto retry_write;
}
if (written != page_size) {
res = -ENOSPC;
free (buffer);
goto unlink_exit;
}
}
free (buffer);
}
return fd;
unlink_exit:
unlink (path);
if (fd > 0) {
close (fd);
}
return res;
} }
int32_t qb_util_circular_mmap(int32_t fd, void **buf, size_t bytes) void
qb_util_stopwatch_stop(qb_util_stopwatch_t * sw)
{ {
void *addr_orig; sw->stopped = qb_util_nano_current_get();
void *addr;
int32_t res;
addr_orig = mmap(NULL, bytes << 1, PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (addr_orig == MAP_FAILED) {
return (-errno);
}
addr = mmap(addr_orig, bytes, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, 0);
if (addr != addr_orig) {
return (-errno);
}
#ifdef QB_BSD
madvise(addr_orig, bytes, MADV_NOSYNC);
#endif
addr = mmap(((char *)addr_orig) + bytes,
bytes, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, 0);
#ifdef QB_BSD
madvise(((char *)addr_orig) + bytes, bytes, MADV_NOSYNC);
#endif
res = close(fd);
if (res) {
return (-errno);
}
*buf = addr_orig;
return (0);
} }
int32_t qb_util_fd_nonblock_cloexec_set(int32_t fd) uint64_t
qb_util_stopwatch_us_elapsed_get(qb_util_stopwatch_t * sw)
{ {
int32_t res; if (sw->stopped == 0 || sw->started == 0) {
char error_str[100]; return 0;
int32_t oldflags = fcntl(fd, F_GETFD, 0);
if (oldflags < 0) {
oldflags = 0;
}
oldflags |= FD_CLOEXEC;
res = fcntl(fd, F_SETFD, oldflags);
if (res == -1) {
res = -errno;
strerror_r(errno, error_str, 100);
qb_util_log(LOG_CRIT,
"Could not set close-on-exit operation on fd: %s
",
error_str);
return res;
} }
return ((sw->stopped - sw->started) / QB_TIME_NS_IN_USEC);
}
res = fcntl(fd, F_SETFL, O_NONBLOCK); float
if (res == -1) { qb_util_stopwatch_sec_elapsed_get(qb_util_stopwatch_t * sw)
res = -errno; {
strerror_r(errno, error_str, 100); uint64_t e6;
qb_util_log(LOG_CRIT, if (sw->stopped == 0 || sw->started == 0) {
"Could not set non-blocking operation on fd: %s" return 0;
,
error_str);
} }
return res; e6 = qb_util_stopwatch_us_elapsed_get(sw);
return ((float)e6 / (float)QB_TIME_US_IN_SEC);
} }
 End of changes. 33 change blocks. 
186 lines changed or deleted 72 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/