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/ |