diff --git a/include/qb/qbhdb.h b/include/qb/qbhdb.h index ce457f6..d9cb83e 100644 --- a/include/qb/qbhdb.h +++ b/include/qb/qbhdb.h @@ -1,178 +1,178 @@ /* * Copyright (C) 2006-2010 Red Hat, Inc. * * Author: Steven Dake * * This file is part of libqb. * * libqb 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. * * libqb 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 libqb. If not, see . */ #ifndef QB_HDB_H_DEFINED #define QB_HDB_H_DEFINED #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif /* *INDENT-OFF* */ #ifdef __cplusplus extern "C" { #endif /* *INDENT-ON* */ #include #include #include #include /** * @file qbhdb.h * The handle database is for reference counting objects. */ /** * Generic handle type is 64 bits. */ typedef uint64_t qb_handle_t; /* * Formatting for string printing on 32/64 bit systems */ #define QB_HDB_D_FORMAT "%"PRIu64 #define QB_HDB_X_FORMAT "%"PRIx64 struct qb_hdb_handle { int32_t state; void *instance; int32_t check; int32_t ref_count; }; struct qb_hdb { uint32_t handle_count; qb_array_t *handles; uint32_t iterator; void (*destructor) (void *); uint32_t first_run; }; /** * Convience macro for declaring a file scoped handle database. * @code * QB_HDB_DECLARE(my_handle_database, NULL); * @endcode */ #define QB_HDB_DECLARE(database_name,destructor_function) \ static struct qb_hdb (database_name) = { \ .handle_count = 0, \ .handles = NULL, \ .iterator = 0, \ .destructor = destructor_function, \ - .first_run = 1 \ + .first_run = QB_TRUE \ }; \ /** * Create a new database. * @param hdb the database to init. */ void qb_hdb_create(struct qb_hdb *hdb); /** * Destroy a handle database. * @param hdb the database to destroy. */ void qb_hdb_destroy(struct qb_hdb *hdb); /** * Create a new handle. * @param hdb the database instance * @param instance_size size of the object to malloc * @param handle_id_out new handle * @return (0 == ok, -errno faliure) */ int32_t qb_hdb_handle_create(struct qb_hdb *hdb, int32_t instance_size, qb_handle_t * handle_id_out); /** * Get the instance associated with this handle and increase it's refcount. * @param handle_in the handle * @param hdb the database instance * @param instance (out) pointer to the desired object. * @return (0 == ok, -errno faliure) */ int32_t qb_hdb_handle_get(struct qb_hdb *hdb, qb_handle_t handle_in, void **instance); /** * Get the instance associated with this handle and increase it's refcount. * @param handle_in the handle * @param hdb the database instance * @param instance (out) pointer to the desired object. * @return (0 == ok, -errno faliure) */ int32_t qb_hdb_handle_get_always(struct qb_hdb *hdb, qb_handle_t handle_in, void **instance); /** * Put the instance associated with this handle and decrease it's refcount. * @param handle_in the handle * @param hdb the database instance * @return (0 == ok, -errno faliure) */ int32_t qb_hdb_handle_put(struct qb_hdb *hdb, qb_handle_t handle_in); /** * Request the destruction of the object. * * When the refcount is 0, it will be destroyed. * * @param handle_in the handle * @param hdb the database instance * @return (0 == ok, -errno faliure) */ int32_t qb_hdb_handle_destroy(struct qb_hdb *hdb, qb_handle_t handle_in); /** * Get the current refcount. * @param handle_in the handle * @param hdb the database instance * @return (>= 0 is the refcount, -errno faliure) */ int32_t qb_hdb_handle_refcount_get(struct qb_hdb *hdb, qb_handle_t handle_in); /** * Reset the iterator. * @param hdb the database instance */ void qb_hdb_iterator_reset(struct qb_hdb *hdb); /** * Get the next object and increament it's refcount. * * Remember to call qb_hdb_handle_put() * * @param hdb the database instance * @param handle (out) the handle * @param instance (out) pointer to the desired object. * @return (0 == ok, -errno faliure) */ int32_t qb_hdb_iterator_next(struct qb_hdb *hdb, void **instance, qb_handle_t * handle); uint32_t qb_hdb_base_convert(qb_handle_t handle); uint64_t qb_hdb_nocheck_convert(uint32_t handle); /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* *INDENT-ON* */ #endif /* QB_HDB_H_DEFINED */ diff --git a/include/tlist.h b/include/tlist.h index bc49a85..bcae55d 100644 --- a/include/tlist.h +++ b/include/tlist.h @@ -1,219 +1,218 @@ /* * Copyright (c) 2006-2007, 2009 Red Hat, Inc. * * Author: Steven Dake * * This file is part of libqb. * * libqb 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. * * libqb 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 libqb. If not, see . */ #ifndef QB_TLIST_H_DEFINED #define QB_TLIST_H_DEFINED #include "os_base.h" #include #include #include #ifndef TIMER_HANDLE typedef void *timer_handle; #define TIMER_HANDLE #endif static int64_t timerlist_hertz; struct timerlist { struct qb_list_head timer_head; }; struct timerlist_timer { struct qb_list_head list; uint64_t expire_time; int32_t is_absolute_timer; void (*timer_fn) (void *data); void *data; timer_handle handle_addr; }; static inline void timerlist_init(struct timerlist *timerlist) { qb_list_init(&timerlist->timer_head); timerlist_hertz = qb_util_nano_monotonic_hz(); } static inline void timerlist_add(struct timerlist *timerlist, struct timerlist_timer *timer) { struct qb_list_head *timer_list = 0; struct timerlist_timer *timer_from_list; - int32_t found; + int32_t found = QB_FALSE; - found = 0; qb_list_for_each(timer_list, &timerlist->timer_head) { timer_from_list = qb_list_entry(timer_list, struct timerlist_timer, list); if (timer_from_list->expire_time > timer->expire_time) { qb_list_add_tail(&timer->list, timer_list); - found = 1; + found = QB_TRUE; break; /* for timer iteration */ } } - if (found == 0) { + if (found == QB_FALSE) { qb_list_add_tail(&timer->list, &timerlist->timer_head); } } static inline int32_t timerlist_add_duration(struct timerlist *timerlist, void (*timer_fn) (void *data), void *data, uint64_t nano_duration, timer_handle * handle) { struct timerlist_timer *timer; timer = (struct timerlist_timer *)malloc(sizeof(struct timerlist_timer)); if (timer == 0) { return -ENOMEM; } timer->expire_time = qb_util_nano_current_get() + nano_duration; - timer->is_absolute_timer = 0; + timer->is_absolute_timer = QB_FALSE; timer->data = data; timer->timer_fn = timer_fn; timer->handle_addr = handle; timerlist_add(timerlist, timer); *handle = timer; return (0); } static inline void timerlist_del(struct timerlist *timerlist, timer_handle _timer_handle) { struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle; memset(timer->handle_addr, 0, sizeof(struct timerlist_timer *)); qb_list_del(&timer->list); qb_list_init(&timer->list); free(timer); } static inline uint64_t timerlist_expire_time(struct timerlist *timerlist, timer_handle _timer_handle) { struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle; return (timer->expire_time); } static inline void timerlist_pre_dispatch(struct timerlist *timerlist, timer_handle _timer_handle) { struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle; memset(timer->handle_addr, 0, sizeof(struct timerlist_timer *)); qb_list_del(&timer->list); qb_list_init(&timer->list); } static inline void timerlist_post_dispatch(struct timerlist *timerlist, timer_handle _timer_handle) { struct timerlist_timer *timer = (struct timerlist_timer *)_timer_handle; free(timer); } /* * returns the number of msec until the next timer will expire for use with poll */ static inline uint64_t timerlist_msec_duration_to_expire(struct timerlist *timerlist) { struct timerlist_timer *timer_from_list; volatile uint64_t current_time; volatile uint64_t msec_duration_to_expire; /* * empty list, no expire */ if (qb_list_empty(&timerlist->timer_head)) { return (-1); } timer_from_list = qb_list_first_entry(&timerlist->timer_head, struct timerlist_timer, list); if (timer_from_list->is_absolute_timer) { current_time = qb_util_nano_from_epoch_get(); } else { current_time = qb_util_nano_current_get(); } /* * timer at head of list is expired, zero msecs required */ if (timer_from_list->expire_time < current_time) { return (0); } msec_duration_to_expire = ((timer_from_list->expire_time - current_time) / QB_TIME_NS_IN_MSEC) + (1000 / timerlist_hertz); return (msec_duration_to_expire); } /* * Expires any timers that should be expired */ static inline void timerlist_expire(struct timerlist *timerlist) { struct timerlist_timer *timer_from_list; struct qb_list_head *pos; struct qb_list_head *next; uint64_t current_time_from_epoch; uint64_t current_monotonic_time; uint64_t current_time; current_monotonic_time = qb_util_nano_current_get(); current_time_from_epoch = current_time = qb_util_nano_from_epoch_get(); qb_list_for_each_safe(pos, next, &timerlist->timer_head) { timer_from_list = qb_list_entry(pos, struct timerlist_timer, list); current_time = (timer_from_list-> is_absolute_timer ? current_time_from_epoch : current_monotonic_time); if (timer_from_list->expire_time < current_time) { timerlist_pre_dispatch(timerlist, timer_from_list); timer_from_list->timer_fn(timer_from_list->data); timerlist_post_dispatch(timerlist, timer_from_list); } else { break; /* for timer iteration */ } } } #endif /* QB_TLIST_H_DEFINED */ diff --git a/lib/hdb.c b/lib/hdb.c index 34cd72e..be227fc 100644 --- a/lib/hdb.c +++ b/lib/hdb.c @@ -1,291 +1,291 @@ /* * Copyright (C) 2006-2010 Red Hat, Inc. * * Author: Steven Dake * * This file is part of libqb. * * libqb 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. * * libqb 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 libqb. If not, see . */ #include "os_base.h" #include #include enum QB_HDB_HANDLE_STATE { QB_HDB_HANDLE_STATE_EMPTY, QB_HDB_HANDLE_STATE_PENDINGREMOVAL, QB_HDB_HANDLE_STATE_ACTIVE }; static void qb_hdb_create_first_run(struct qb_hdb *hdb) { - if (hdb->first_run == 1) { - hdb->first_run = 0; + if (hdb->first_run == QB_TRUE) { + hdb->first_run = QB_FALSE; qb_atomic_init(); hdb->handles = qb_array_create(32, sizeof(struct qb_hdb_handle)); } } void qb_hdb_create(struct qb_hdb *hdb) { memset(hdb, 0, sizeof(struct qb_hdb)); - hdb->first_run = 1; + hdb->first_run = QB_TRUE; qb_hdb_create_first_run(hdb); } void qb_hdb_destroy(struct qb_hdb *hdb) { qb_array_free(hdb->handles); memset(hdb, 0, sizeof(struct qb_hdb)); } int32_t qb_hdb_handle_create(struct qb_hdb *hdb, int32_t instance_size, qb_handle_t * handle_id_out) { int32_t handle; int32_t res = 0; uint32_t check; - int32_t found = 0; + int32_t found = QB_FALSE; void *instance; int32_t i; struct qb_hdb_handle *entry = NULL; int32_t handle_count; qb_hdb_create_first_run(hdb); handle_count = qb_atomic_int_get(&hdb->handle_count); for (handle = 0; handle < handle_count; handle++) { if (qb_array_index(hdb->handles, handle, (void**)&entry) == 0 && entry->state == QB_HDB_HANDLE_STATE_EMPTY) { - found = 1; + found = QB_TRUE; qb_atomic_int_inc(&entry->ref_count); break; } } - if (found == 0) { + if (found == QB_FALSE) { res = qb_array_grow(hdb->handles, handle_count + 1); if (res != 0) { return res; } res = qb_array_index(hdb->handles, handle_count, (void **)&entry); if (res != 0) { return res; } qb_atomic_int_inc((int32_t *)&hdb->handle_count); } instance = malloc(instance_size); if (instance == 0) { return -ENOMEM; } /* * This code makes sure the random number isn't zero * We use 0 to specify an invalid handle out of the 1^64 address space * If we get 0 200 times in a row, the RNG may be broken */ for (i = 0; i < 200; i++) { check = random(); if (check != 0 && check != 0xffffffff) { break; } } memset(instance, 0, instance_size); entry->state = QB_HDB_HANDLE_STATE_ACTIVE; entry->instance = instance; entry->ref_count = 1; entry->check = check; *handle_id_out = (((uint64_t) (check)) << 32) | handle; return res; } int32_t qb_hdb_handle_get(struct qb_hdb * hdb, qb_handle_t handle_in, void **instance) { uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32)); uint32_t handle = handle_in & 0xffffffff; struct qb_hdb_handle *entry; int32_t handle_count; qb_hdb_create_first_run(hdb); *instance = NULL; handle_count = qb_atomic_int_get(&hdb->handle_count); if (handle >= handle_count) { return (-EBADF); } if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 || entry->state != QB_HDB_HANDLE_STATE_ACTIVE) { return (-EBADF); } if (check != 0xffffffff && check != entry->check) { return (-EBADF); } qb_atomic_int_inc(&entry->ref_count); *instance = entry->instance; return (0); } int32_t qb_hdb_handle_get_always(struct qb_hdb * hdb, qb_handle_t handle_in, void **instance) { return qb_hdb_handle_get(hdb, handle_in, instance); } int32_t qb_hdb_handle_put(struct qb_hdb * hdb, qb_handle_t handle_in) { uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32)); uint32_t handle = handle_in & 0xffffffff; struct qb_hdb_handle *entry; int32_t handle_count; qb_hdb_create_first_run(hdb); handle_count = qb_atomic_int_get(&hdb->handle_count); if (handle >= handle_count) { return (-EBADF); } if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 || (check != 0xffffffff && check != entry->check)) { return (-EBADF); } if (qb_atomic_int_dec_and_test(&entry->ref_count)) { if (hdb->destructor) { hdb->destructor(entry->instance); } free(entry->instance); memset(entry, 0, sizeof(struct qb_hdb_handle)); } return (0); } int32_t qb_hdb_handle_destroy(struct qb_hdb * hdb, qb_handle_t handle_in) { uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32)); uint32_t handle = handle_in & 0xffffffff; int32_t res; struct qb_hdb_handle *entry; int32_t handle_count; qb_hdb_create_first_run(hdb); handle_count = qb_atomic_int_get(&hdb->handle_count); if (handle >= handle_count) { return (-EBADF); } if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 || (check != 0xffffffff && check != entry->check)) { return (-EBADF); } entry->state = QB_HDB_HANDLE_STATE_PENDINGREMOVAL; res = qb_hdb_handle_put(hdb, handle_in); return (res); } int32_t qb_hdb_handle_refcount_get(struct qb_hdb * hdb, qb_handle_t handle_in) { uint32_t check = ((uint32_t) (((uint64_t) handle_in) >> 32)); uint32_t handle = handle_in & 0xffffffff; struct qb_hdb_handle *entry; int32_t handle_count; int32_t refcount = 0; qb_hdb_create_first_run(hdb); handle_count = qb_atomic_int_get(&hdb->handle_count); if (handle >= handle_count) { return (-EBADF); } if (qb_array_index(hdb->handles, handle, (void **)&entry) != 0 || (check != 0xffffffff && check != entry->check)) { return (-EBADF); } refcount = qb_atomic_int_get(&entry->ref_count); return (refcount); } void qb_hdb_iterator_reset(struct qb_hdb *hdb) { hdb->iterator = 0; } int32_t qb_hdb_iterator_next(struct qb_hdb *hdb, void **instance, qb_handle_t * handle) { int32_t res = -1; uint64_t checker; struct qb_hdb_handle *entry; int32_t handle_count; handle_count = qb_atomic_int_get(&hdb->handle_count); while (hdb->iterator < handle_count) { res = qb_array_index(hdb->handles, hdb->iterator, (void **)&entry); if (res != 0) { break; } checker = (uint64_t) (entry->check); *handle = (checker << 32) | hdb->iterator; res = qb_hdb_handle_get(hdb, *handle, instance); hdb->iterator += 1; if (res == 0) { break; } } return (res); } uint32_t qb_hdb_base_convert(qb_handle_t handle) { return (handle & 0xffffffff); } uint64_t qb_hdb_nocheck_convert(uint32_t handle) { uint64_t retvalue = 0xffffffffULL << 32 | handle; return (retvalue); } diff --git a/lib/log_format.c b/lib/log_format.c index 34238f1..a8b3239 100644 --- a/lib/log_format.c +++ b/lib/log_format.c @@ -1,842 +1,842 @@ /* * Copyright (C) 2011 Red Hat, Inc. * * All rights reserved. * * Author: Angus Salkeld * * libqb 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. * * libqb 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 libqb. If not, see . */ #include "os_base.h" #include #include #include "log_int.h" static qb_log_tags_stringify_fn _user_tags_stringify_fn; /* * syslog prioritynames, facility names to value mapping * Some C libraries build this in to their headers, but it is non-portable * so logsys supplies its own version. */ struct syslog_names { const char *c_name; int32_t c_val; }; static struct syslog_names prioritynames[] = { {"emerg", LOG_EMERG}, {"alert", LOG_ALERT}, {"crit", LOG_CRIT}, {"error", LOG_ERR}, {"warning", LOG_WARNING}, {"notice", LOG_NOTICE}, {"info", LOG_INFO}, {"debug", LOG_DEBUG}, {"trace", LOG_TRACE}, {NULL, -1} }; struct syslog_names facilitynames[] = { {"auth", LOG_AUTH}, #if defined(LOG_AUTHPRIV) {"authpriv", LOG_AUTHPRIV}, #endif {"cron", LOG_CRON}, {"daemon", LOG_DAEMON}, #if defined(LOG_FTP) {"ftp", LOG_FTP}, #endif {"kern", LOG_KERN}, {"lpr", LOG_LPR}, {"mail", LOG_MAIL}, {"news", LOG_NEWS}, {"syslog", LOG_SYSLOG}, {"user", LOG_USER}, {"uucp", LOG_UUCP}, {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, {"local2", LOG_LOCAL2}, {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4}, {"local5", LOG_LOCAL5}, {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7}, {NULL, -1} }; static const char log_month_name[][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static pthread_rwlock_t _formatlock; void qb_log_format_init(void) { int32_t i; struct qb_log_target *t; i = pthread_rwlock_init(&_formatlock, NULL); assert(i == 0); for (i = 0; i < QB_LOG_TARGET_MAX; i++) { t = qb_log_target_get(i); t->format = strdup("[%p] %b"); } } void qb_log_format_fini(void) { struct qb_log_target *t; int32_t i; pthread_rwlock_destroy(&_formatlock); for (i = 0; i < QB_LOG_TARGET_MAX; i++) { t = qb_log_target_get(i); free(t->format); } } void qb_log_format_set(int32_t target, const char *format) { char modified_format[256]; struct qb_log_target *t = qb_log_target_get(target); pthread_rwlock_wrlock(&_formatlock); free(t->format); if (format) { qb_log_target_format_static(target, format, modified_format); t->format = strdup(modified_format); } else { t->format = strdup("[%p] %b"); } assert(t->format != NULL); pthread_rwlock_unlock(&_formatlock); } /* Convert string "auth" to equivalent number "LOG_AUTH" etc. */ int32_t qb_log_facility2int(const char *fname) { int32_t i; if (fname == NULL) { return -EINVAL; } for (i = 0; facilitynames[i].c_name != NULL; i++) { if (strcmp(fname, facilitynames[i].c_name) == 0) { return facilitynames[i].c_val; } } return -EINVAL; } /* Convert number "LOG_AUTH" to equivalent string "auth" etc. */ const char * qb_log_facility2str(int32_t fnum) { int32_t i; for (i = 0; facilitynames[i].c_name != NULL; i++) { if (facilitynames[i].c_val == fnum) { return facilitynames[i].c_name; } } return NULL; } const char * qb_log_priority2str(uint8_t priority) { if (priority > LOG_TRACE) { return prioritynames[LOG_TRACE].c_name; } return prioritynames[priority].c_name; } void qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn) { _user_tags_stringify_fn = fn; } static int _strcpy_cutoff(char *dest, const char *src, size_t cutoff, int ralign, size_t buf_len) { size_t len = strlen(src); if (buf_len <= 1) { if (buf_len == 0) dest[0] = 0; return 0; } if (cutoff == 0) { cutoff = len; } cutoff = QB_MIN(cutoff, buf_len - 1); len = QB_MIN(len, cutoff); if (ralign) { memset(dest, ' ', cutoff - len); memcpy(dest + cutoff - len, src, len); } else { memcpy(dest, src, len); memset(dest + len, ' ', cutoff - len); } dest[cutoff] = '\0'; return cutoff; } /* * This function will do static formatting (for things that don't * change on each log message). * * %P PID * %N name passed into qb_log_init * %H hostname * * any number between % and character specify field length to pad or chop */ void qb_log_target_format_static(int32_t target, const char * format, char *output_buffer) { char tmp_buf[255]; unsigned int format_buffer_idx = 0; unsigned int output_buffer_idx = 0; size_t cutoff; uint32_t len; int ralign; int c; struct qb_log_target *t = qb_log_target_get(target); if (format == NULL) { return; } while ((c = format[format_buffer_idx])) { cutoff = 0; - ralign = 0; + ralign = QB_FALSE; if (c != '%') { output_buffer[output_buffer_idx++] = c; format_buffer_idx++; } else { const char *p; unsigned int percent_buffer_idx = format_buffer_idx; format_buffer_idx += 1; if (format[format_buffer_idx] == '-') { - ralign = 1; + ralign = QB_TRUE; format_buffer_idx += 1; } if (isdigit(format[format_buffer_idx])) { cutoff = atoi(&format[format_buffer_idx]); } while (isdigit(format[format_buffer_idx])) { format_buffer_idx += 1; } switch (format[format_buffer_idx]) { case 'P': snprintf(tmp_buf, 30, "%d", getpid()); p = tmp_buf; break; case 'N': p = t->name; break; case 'H': if (gethostname(tmp_buf, 255) == 0) { tmp_buf[254] = '\0'; } else { (void)strlcpy(tmp_buf, "localhost", 255); } p = tmp_buf; break; default: p = &format[percent_buffer_idx]; cutoff = (format_buffer_idx - percent_buffer_idx + 1); - ralign = 0; + ralign = QB_FALSE; break; } len = _strcpy_cutoff(output_buffer + output_buffer_idx, p, cutoff, ralign, (QB_LOG_MAX_LEN - output_buffer_idx)); output_buffer_idx += len; format_buffer_idx += 1; } if (output_buffer_idx >= QB_LOG_MAX_LEN - 1) { break; } } output_buffer[output_buffer_idx] = '\0'; } /* * %n FUNCTION NAME * %f FILENAME * %l FILELINE * %p PRIORITY * %t TIMESTAMP * %b BUFFER * %g SUBSYSTEM * * any number between % and character specify field length to pad or chop */ void qb_log_target_format(int32_t target, struct qb_log_callsite *cs, time_t current_time, const char *formatted_message, char *output_buffer) { char tmp_buf[128]; struct tm tm_res; unsigned int format_buffer_idx = 0; unsigned int output_buffer_idx = 0; size_t cutoff; uint32_t len; int ralign; int c; struct qb_log_target *t = qb_log_target_get(target); pthread_rwlock_rdlock(&_formatlock); if (t->format == NULL) { pthread_rwlock_unlock(&_formatlock); return; } while ((c = t->format[format_buffer_idx])) { cutoff = 0; - ralign = 0; + ralign = QB_FALSE; if (c != '%') { output_buffer[output_buffer_idx++] = c; format_buffer_idx++; } else { const char *p; format_buffer_idx += 1; if (t->format[format_buffer_idx] == '-') { - ralign = 1; + ralign = QB_TRUE; format_buffer_idx += 1; } if (isdigit(t->format[format_buffer_idx])) { cutoff = atoi(&t->format[format_buffer_idx]); } while (isdigit(t->format[format_buffer_idx])) { format_buffer_idx += 1; } switch (t->format[format_buffer_idx]) { case 'g': if (_user_tags_stringify_fn) { p = _user_tags_stringify_fn(cs->tags); } else { p = ""; } break; case 'n': p = cs->function; break; case 'f': #ifdef BUILDING_IN_PLACE p = cs->filename; #else p = strrchr(cs->filename, '/'); if (p == NULL) { p = cs->filename; } else { p++; /* move past the "/" */ } #endif /* BUILDING_IN_PLACE */ break; case 'l': snprintf(tmp_buf, 30, "%d", cs->lineno); p = tmp_buf; break; case 't': (void)localtime_r(¤t_time, &tm_res); snprintf(tmp_buf, TIME_STRING_SIZE, "%s %02d %02d:%02d:%02d", log_month_name[tm_res.tm_mon], tm_res.tm_mday, tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec); p = tmp_buf; break; case 'b': p = formatted_message; break; case 'p': if (cs->priority > LOG_TRACE) { p = prioritynames[LOG_TRACE].c_name; } else { p = prioritynames[cs->priority].c_name; } break; default: p = ""; break; } len = _strcpy_cutoff(output_buffer + output_buffer_idx, p, cutoff, ralign, (QB_LOG_MAX_LEN - output_buffer_idx)); output_buffer_idx += len; format_buffer_idx += 1; } if (output_buffer_idx >= QB_LOG_MAX_LEN - 1) { break; } } pthread_rwlock_unlock(&_formatlock); if (output_buffer[output_buffer_idx - 1] == '\n') { output_buffer[output_buffer_idx - 1] = '\0'; } else { output_buffer[output_buffer_idx] = '\0'; } } /* * These wrappers around strl* functions just return the * number of characters written, not the number of characters * requested to be written. */ static size_t my_strlcpy(char *dest, const char * src, size_t maxlen) { size_t rc = strlcpy(dest, src, maxlen); /* maxlen includes NUL, so -1 */ return QB_MIN(rc, maxlen-1); } static size_t my_strlcat(char *dest, const char * src, size_t maxlen) { size_t rc = strlcat(dest, src, maxlen); return QB_MIN(rc, maxlen-1); } size_t qb_vsnprintf_serialize(char *serialize, size_t max_len, const char *fmt, va_list ap) { char *format; char *p; - int type_long = 0; - int type_longlong = 0; + int type_long = QB_FALSE; + int type_longlong = QB_FALSE; int sformat_length = 0; - int sformat_precision = 0; + int sformat_precision = QB_FALSE; uint32_t location = my_strlcpy(serialize, fmt, max_len) + 1; format = (char *)fmt; for (;;) { - type_long = 0; - type_longlong = 0; + type_long = QB_FALSE; + type_longlong = QB_FALSE; p = strchrnul((const char *)format, '%'); if (*p == '\0') { break; } format = p + 1; reprocess: switch (format[0]) { case '#': /* alternate form conversion, ignore */ case '-': /* left adjust, ignore */ case ' ': /* a space, ignore */ case '+': /* a sign should be used, ignore */ case '\'': /* group in thousands, ignore */ case 'I': /* glibc-ism locale alternative, ignore */ format++; goto reprocess; case '.': /* precision, ignore */ format++; - sformat_precision = 1; + sformat_precision = QB_TRUE; goto reprocess; case '0': /* field width, ignore */ case '1': /* field width, ignore */ case '2': /* field width, ignore */ case '3': /* field width, ignore */ case '4': /* field width, ignore */ case '5': /* field width, ignore */ case '6': /* field width, ignore */ case '7': /* field width, ignore */ case '8': /* field width, ignore */ case '9': /* field width, ignore */ if (sformat_precision) { sformat_length *= 10; sformat_length += (format[0] - '0'); } format++; goto reprocess; case '*': /* variable field width, save */ { int arg_int = va_arg(ap, int); if (location + sizeof (int) > max_len) { return max_len; } memcpy(&serialize[location], &arg_int, sizeof (int)); location += sizeof(int); format++; goto reprocess; } case 'l': format++; - type_long = 1; + type_long = QB_TRUE; if (*format == 'l') { - type_long = 0; - type_longlong = 1; + type_long = QB_FALSE; + type_longlong = QB_TRUE; format++; } goto reprocess; case 'd': /* int argument */ case 'i': /* int argument */ case 'o': /* unsigned int argument */ case 'u': case 'x': case 'X': if (type_long) { long int arg_int; if (location + sizeof (long int) > max_len) { return max_len; } arg_int = va_arg(ap, long int); memcpy(&serialize[location], &arg_int, sizeof(long int)); location += sizeof(long int); format++; break; } else if (type_longlong) { long long int arg_int; if (location + sizeof (long long int) > max_len) { return max_len; } arg_int = va_arg(ap, long long int); memcpy(&serialize[location], &arg_int, sizeof(long long int)); location += sizeof(long long int); format++; break; } else { int arg_int; if (location + sizeof (int) > max_len) { return max_len; } arg_int = va_arg(ap, int); memcpy(&serialize[location], &arg_int, sizeof(int)); location += sizeof(int); format++; break; } case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': { double arg_double; if (location + sizeof (double) > max_len) { return max_len; } arg_double = va_arg(ap, double); memcpy (&serialize[location], &arg_double, sizeof (double)); location += sizeof(double); format++; break; } case 'c': { int arg_int; unsigned char arg_char; if (location + sizeof (unsigned int) > max_len) { return max_len; } arg_int = va_arg(ap, unsigned int); arg_char = (unsigned char)arg_int; memcpy (&serialize[location], &arg_char, sizeof (unsigned char)); location += sizeof(unsigned char); break; } case 's': { char *arg_string; arg_string = va_arg(ap, char *); if (arg_string == NULL) { location += my_strlcpy(&serialize[location], "(null)", QB_MIN(strlen("(null)") + 1, max_len - location)); } else if (sformat_length) { location += my_strlcpy(&serialize[location], arg_string, QB_MIN(sformat_length + 1, (max_len - location))); } else { location += my_strlcpy(&serialize[location], arg_string, QB_MIN(strlen(arg_string) + 1, max_len - location)); } location++; break; } case 'p': { ptrdiff_t arg_pointer = va_arg(ap, ptrdiff_t); if (location + sizeof (ptrdiff_t) > max_len) { return max_len; } memcpy(&serialize[location], &arg_pointer, sizeof(ptrdiff_t)); location += sizeof(ptrdiff_t); break; } case '%': if (location + 1 > max_len) { return max_len; } serialize[location++] = '%'; sformat_length = 0; - sformat_precision = 0; + sformat_precision = QB_FALSE; break; } } return (location); } #define MINI_FORMAT_STR_LEN 20 size_t qb_vsnprintf_deserialize(char *string, size_t str_len, const char *buf) { char *p; char *format; char fmt[MINI_FORMAT_STR_LEN]; int fmt_pos; uint32_t location = 0; uint32_t data_pos = strlen(buf) + 1; - int type_long = 0; - int type_longlong = 0; + int type_long = QB_FALSE; + int type_longlong = QB_FALSE; int len; string[0] = '\0'; format = (char *)buf; for (;;) { - type_long = 0; - type_longlong = 0; + type_long = QB_FALSE; + type_longlong = QB_FALSE; p = strchrnul((const char *)format, '%'); if (*p == '\0') { return my_strlcat(string, format, str_len) + 1; } /* copy from current to the next % */ len = p - format; memcpy(&string[location], format, len); location += len; format = p; /* start building up the format for snprintf */ fmt_pos = 0; fmt[fmt_pos++] = *format; format++; reprocess: switch (format[0]) { case '#': /* alternate form conversion, ignore */ case '-': /* left adjust, ignore */ case ' ': /* a space, ignore */ case '+': /* a sign should be used, ignore */ case '\'': /* group in thousands, ignore */ case 'I': /* glibc-ism locale alternative, ignore */ case '.': /* precision, ignore */ case '0': /* field width, ignore */ case '1': /* field width, ignore */ case '2': /* field width, ignore */ case '3': /* field width, ignore */ case '4': /* field width, ignore */ case '5': /* field width, ignore */ case '6': /* field width, ignore */ case '7': /* field width, ignore */ case '8': /* field width, ignore */ case '9': /* field width, ignore */ fmt[fmt_pos++] = *format; format++; goto reprocess; case '*': { int arg_int; memcpy(&arg_int, &buf[data_pos], sizeof(int)); data_pos += sizeof(int); fmt_pos += snprintf(&fmt[fmt_pos], MINI_FORMAT_STR_LEN - fmt_pos, "%d", arg_int); format++; goto reprocess; } case 'l': fmt[fmt_pos++] = *format; format++; - type_long = 1; + type_long = QB_TRUE; if (*format == 'l') { - type_long = 0; - type_longlong = 1; + type_long = QB_FALSE; + type_longlong = QB_TRUE; } goto reprocess; case 'd': /* int argument */ case 'i': /* int argument */ case 'o': /* unsigned int argument */ case 'u': case 'x': case 'X': if (type_long) { long int arg_int; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; memcpy(&arg_int, &buf[data_pos], sizeof(long int)); location += snprintf(&string[location], str_len - location, fmt, arg_int); data_pos += sizeof(long int); format++; break; } else if (type_longlong) { long long int arg_int; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; memcpy(&arg_int, &buf[data_pos], sizeof(long long int)); location += snprintf(&string[location], str_len - location, fmt, arg_int); data_pos += sizeof(long long int); format++; break; } else { int arg_int; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; memcpy(&arg_int, &buf[data_pos], sizeof(int)); location += snprintf(&string[location], str_len - location, fmt, arg_int); data_pos += sizeof(int); format++; break; } case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': { double arg_double; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; memcpy(&arg_double, &buf[data_pos], sizeof(double)); location += snprintf(&string[location], str_len - location, fmt, arg_double); data_pos += sizeof(double); format++; break; } case 'c': { unsigned char *arg_char; fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; arg_char = (unsigned char*)&buf[data_pos]; location += snprintf(&string[location], str_len - location, fmt, *arg_char); data_pos += sizeof(unsigned char); format++; break; } case 's': { fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; len = snprintf(&string[location], str_len - location, fmt, &buf[data_pos]); location += len; /* don't use len as there might be a len modifier */ data_pos += strlen(&buf[data_pos]) + 1; format++; break; } case 'p': { ptrdiff_t pt; memcpy(&pt, &buf[data_pos], sizeof(ptrdiff_t)); fmt[fmt_pos++] = *format; fmt[fmt_pos++] = '\0'; location += snprintf(&string[location], str_len - location, fmt, pt); data_pos += sizeof(void*); format++; break; } case '%': string[location++] = '%'; format++; break; } } return location; } diff --git a/lib/log_thread.c b/lib/log_thread.c index 3dffef9..0a97c6e 100644 --- a/lib/log_thread.c +++ b/lib/log_thread.c @@ -1,279 +1,279 @@ /* * Copyright (C) 2011 Red Hat, Inc. * * All rights reserved. * * Author: Angus Salkeld * * libqb 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. * * libqb 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 libqb. If not, see . */ #include "os_base.h" #include #include #include #include #include #include "log_int.h" -static int wthread_active = 0; +static int wthread_active = QB_FALSE; -static int wthread_should_exit = 0; +static int wthread_should_exit = QB_FALSE; static qb_thread_lock_t *logt_wthread_lock = NULL; static QB_LIST_DECLARE(logt_print_finished_records); static int logt_memory_used = 0; static int logt_dropped_messages = 0; static sem_t logt_thread_start; static sem_t logt_print_finished; static int logt_sched_param_queued = QB_FALSE; static int logt_sched_policy; #if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX) static struct sched_param logt_sched_param; #endif /* HAVE_PTHREAD_SETSCHEDPARAM && HAVE_SCHED_GET_PRIORITY_MAX */ static pthread_t logt_thread_id = 0; static void *qb_logt_worker_thread(void *data) __attribute__ ((noreturn)); static void * qb_logt_worker_thread(void *data) { struct qb_log_record *rec; int dropped = 0; int res; /* * Signal wthread_create that the initialization process may continue */ sem_post(&logt_thread_start); for (;;) { retry_sem_wait: res = sem_wait(&logt_print_finished); if (res == -1 && errno == EINTR) { goto retry_sem_wait; } else if (res == -1) { /* * This case shouldn't happen */ pthread_exit(NULL); } (void)qb_thread_lock(logt_wthread_lock); if (wthread_should_exit) { int value = -1; (void)sem_getvalue(&logt_print_finished, &value); if (value == 0) { (void)qb_thread_unlock(logt_wthread_lock); pthread_exit(NULL); } } rec = qb_list_first_entry(&logt_print_finished_records, struct qb_log_record, list); qb_list_del(&rec->list); logt_memory_used = logt_memory_used - strlen(rec->buffer) - sizeof(struct qb_log_record) - 1; dropped = logt_dropped_messages; logt_dropped_messages = 0; (void)qb_thread_unlock(logt_wthread_lock); if (dropped) { printf("%d messages lost\n", dropped); } qb_log_thread_log_write(rec->cs, rec->timestamp, rec->buffer); free(rec->buffer); free(rec); } } int32_t qb_log_thread_priority_set(int32_t policy, int32_t priority) { int res = 0; #if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX) logt_sched_policy = policy; if (policy == SCHED_OTHER #ifdef SCHED_IDLE || policy == SCHED_IDLE #endif #if defined(SCHED_BATCH) && !defined(QB_DARWIN) || policy == SCHED_BATCH #endif ) { logt_sched_param.sched_priority = 0; } else { logt_sched_param.sched_priority = priority; } - if (wthread_active == 0) { + if (wthread_active == QB_FALSE) { logt_sched_param_queued = QB_TRUE; } else { res = pthread_setschedparam(logt_thread_id, policy, &logt_sched_param); if (res != 0) { res = -res; } } #endif return res; } int32_t qb_log_thread_start(void) { int res; if (wthread_active) { return 0; } - wthread_active = 1; + wthread_active = QB_TRUE; sem_init(&logt_thread_start, 0, 0); sem_init(&logt_print_finished, 0, 0); res = pthread_create(&logt_thread_id, NULL, qb_logt_worker_thread, NULL); if (res != 0) { - wthread_active = 0; + wthread_active = QB_FALSE; return -res; } sem_wait(&logt_thread_start); if (logt_sched_param_queued) { res = qb_log_thread_priority_set(logt_sched_policy, logt_sched_param.sched_priority); if (res != 0) { goto cleanup_pthread; } logt_sched_param_queued = QB_FALSE; } logt_wthread_lock = qb_thread_lock_create(QB_THREAD_LOCK_SHORT); if (logt_wthread_lock == NULL) { goto cleanup_pthread; } return 0; cleanup_pthread: - wthread_should_exit = 1; + wthread_should_exit = QB_TRUE; sem_post(&logt_print_finished); pthread_join(logt_thread_id, NULL); sem_destroy(&logt_print_finished); sem_destroy(&logt_thread_start); return res; } void qb_log_thread_log_post(struct qb_log_callsite *cs, time_t timestamp, const char *buffer) { struct qb_log_record *rec; size_t buf_size; size_t total_size; rec = malloc(sizeof(struct qb_log_record)); if (rec == NULL) { return; } buf_size = strlen(buffer) + 1; total_size = sizeof(struct qb_log_record) + buf_size; rec->cs = cs; rec->buffer = malloc(buf_size); if (rec->buffer == NULL) { goto free_record; } memcpy(rec->buffer, buffer, buf_size); rec->timestamp = timestamp; qb_list_init(&rec->list); (void)qb_thread_lock(logt_wthread_lock); logt_memory_used += total_size; if (logt_memory_used > 512000) { free(rec->buffer); free(rec); logt_memory_used = logt_memory_used - total_size; logt_dropped_messages += 1; (void)qb_thread_unlock(logt_wthread_lock); return; } else { qb_list_add_tail(&rec->list, &logt_print_finished_records); } (void)qb_thread_unlock(logt_wthread_lock); sem_post(&logt_print_finished); return; free_record: free(rec); } void qb_log_thread_stop(void) { int res; int value; struct qb_log_record *rec; - if (wthread_active == 0 && logt_wthread_lock == NULL) { + if (wthread_active == QB_FALSE && logt_wthread_lock == NULL) { return; } - if (wthread_active == 0) { + if (wthread_active == QB_FALSE) { for (;;) { res = sem_getvalue(&logt_print_finished, &value); if (res != 0 || value == 0) { return; } sem_wait(&logt_print_finished); (void)qb_thread_lock(logt_wthread_lock); rec = qb_list_first_entry(&logt_print_finished_records, struct qb_log_record, list); qb_list_del(&rec->list); logt_memory_used = logt_memory_used - strlen(rec->buffer) - sizeof(struct qb_log_record) - 1; (void)qb_thread_unlock(logt_wthread_lock); qb_log_thread_log_write(rec->cs, rec->timestamp, rec->buffer); free(rec->buffer); free(rec); } } else { - wthread_should_exit = 1; + wthread_should_exit = QB_TRUE; sem_post(&logt_print_finished); pthread_join(logt_thread_id, NULL); } (void)qb_thread_lock_destroy(logt_wthread_lock); sem_destroy(&logt_print_finished); sem_destroy(&logt_thread_start); } diff --git a/lib/loop_poll.c b/lib/loop_poll.c index 30f8666..e852fa2 100644 --- a/lib/loop_poll.c +++ b/lib/loop_poll.c @@ -1,770 +1,770 @@ /* * Copyright (C) 2010 Red Hat, Inc. * * Author: Angus Salkeld * * This file is part of libqb. * * libqb 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. * * libqb 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 libqb. If not, see . */ #include "os_base.h" #ifdef HAVE_SYS_RESOURCE_H #include #endif #include #include "loop_poll_int.h" /* * Define this to log slow (>10ms) jobs. */ #undef DEBUG_DISPATCH_TIME /* logs, std(in|out|err), pipe */ #define POLL_FDS_USED_MISC 50 #ifdef HAVE_EPOLL #define USE_EPOLL 1 #else #ifdef HAVE_KQUEUE #define USE_KQUEUE 1 #else #define USE_POLL 1 #endif /* HAVE_KQUEUE */ #endif /* HAVE_EPOLL */ static int32_t _qb_signal_add_to_jobs_(struct qb_loop *l, struct qb_poll_entry *pe); static void _poll_entry_check_generate_(struct qb_poll_entry *pe) { int32_t i; for (i = 0; i < 200; i++) { pe->check = random(); if (pe->check != 0 && pe->check != 0xffffffff) { break; } } } static void _poll_entry_mark_deleted_(struct qb_poll_entry *pe) { pe->ufd.fd = -1; pe->state = QB_POLL_ENTRY_DELETED; pe->check = 0; } static void _poll_entry_empty_(struct qb_poll_entry *pe) { memset(pe, 0, sizeof(struct qb_poll_entry)); pe->ufd.fd = -1; } static void _poll_dispatch_and_take_back_(struct qb_loop_item *item, enum qb_loop_priority p) { struct qb_poll_entry *pe = (struct qb_poll_entry *)item; int32_t res; #ifdef DEBUG_DISPATCH_TIME uint64_t start; uint64_t stop; int32_t log_warn = QB_FALSE; start = qb_util_nano_current_get(); #endif /* DEBUG_DISPATCH_TIME */ assert(pe->state == QB_POLL_ENTRY_JOBLIST); assert(pe->item.type == QB_LOOP_FD); res = pe->poll_dispatch_fn(pe->ufd.fd, pe->ufd.revents, pe->item.user_data); if (res < 0) { _poll_entry_mark_deleted_(pe); } else { pe->state = QB_POLL_ENTRY_ACTIVE; pe->ufd.revents = 0; } #ifdef DEBUG_DISPATCH_TIME if (pe->state == QB_POLL_ENTRY_ACTIVE) { pe->runs++; if ((pe->runs % 50) == 0) { log_warn = QB_TRUE; } stop = qb_util_nano_current_get(); if ((stop - start) > (10 * QB_TIME_NS_IN_MSEC)) { log_warn = QB_TRUE; } if (log_warn && pe->item.type == QB_LOOP_FD) { qb_util_log(LOG_INFO, "[fd:%d] dispatch:%p runs:%d duration:%d ms", pe->ufd.fd, pe->poll_dispatch_fn, pe->runs, (int32_t) ((stop - start) / QB_TIME_NS_IN_MSEC)); } } #endif /* DEBUG_DISPATCH_TIME */ } void qb_poll_fds_usage_check_(struct qb_poll_source *s) { struct rlimit lim; static int32_t socks_limit = 0; - int32_t send_event = 0; + int32_t send_event = QB_FALSE; int32_t socks_used = 0; int32_t socks_avail = 0; struct qb_poll_entry *pe; int32_t i; if (socks_limit == 0) { if (getrlimit(RLIMIT_NOFILE, &lim) == -1) { qb_util_perror(LOG_WARNING, "getrlimit"); return; } socks_limit = lim.rlim_cur; socks_limit -= POLL_FDS_USED_MISC; if (socks_limit < 0) { socks_limit = 0; } } for (i = 0; i < s->poll_entry_count; i++) { assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0); if ((pe->state == QB_POLL_ENTRY_ACTIVE || pe->state == QB_POLL_ENTRY_JOBLIST) && pe->ufd.fd != -1) { socks_used++; } if (pe->state == QB_POLL_ENTRY_DELETED) { _poll_entry_empty_(pe); } } socks_avail = socks_limit - socks_used; if (socks_avail < 0) { socks_avail = 0; } - send_event = 0; + send_event = QB_FALSE; if (s->not_enough_fds) { if (socks_avail > 2) { - s->not_enough_fds = 0; - send_event = 1; + s->not_enough_fds = QB_FALSE; + send_event = QB_TRUE; } } else { if (socks_avail <= 1) { - s->not_enough_fds = 1; - send_event = 1; + s->not_enough_fds = QB_TRUE; + send_event = QB_TRUE; } } if (send_event && s->low_fds_event_fn) { s->low_fds_event_fn(s->not_enough_fds, socks_avail); } } struct qb_loop_source * qb_loop_poll_create(struct qb_loop *l) { struct qb_poll_source *s = malloc(sizeof(struct qb_poll_source)); if (s == NULL) { return NULL; } s->s.l = l; s->s.dispatch_and_take_back = _poll_dispatch_and_take_back_; s->poll_entries = qb_array_create_2(16, sizeof(struct qb_poll_entry), 16); s->poll_entry_count = 0; s->low_fds_event_fn = NULL; - s->not_enough_fds = 0; + s->not_enough_fds = QB_FALSE; #ifdef USE_EPOLL (void)qb_epoll_init(s); #endif #ifdef USE_KQUEUE (void)qb_kqueue_init(s); #endif #ifdef USE_POLL (void)qb_poll_init(s); #endif /* USE_POLL */ return (struct qb_loop_source *)s; } void qb_loop_poll_destroy(struct qb_loop *l) { struct qb_poll_source *s = (struct qb_poll_source *)l->fd_source; qb_array_free(s->poll_entries); s->driver.fini(s); free(s); } int32_t qb_loop_poll_low_fds_event_set(struct qb_loop *l, qb_loop_poll_low_fds_event_fn fn) { struct qb_poll_source *s = (struct qb_poll_source *)l->fd_source; s->low_fds_event_fn = fn; return 0; } static int32_t _get_empty_array_position_(struct qb_poll_source *s) { - int32_t found = 0; + int32_t found = QB_FALSE; uint32_t install_pos; int32_t res = 0; struct qb_poll_entry *pe; - for (found = 0, install_pos = 0; + for (install_pos = 0; install_pos < s->poll_entry_count; install_pos++) { assert(qb_array_index (s->poll_entries, install_pos, (void **)&pe) == 0); if (pe->state == QB_POLL_ENTRY_EMPTY) { - found = 1; + found = QB_TRUE; break; } } - if (found == 0) { + if (found == QB_FALSE) { #ifdef USE_POLL struct pollfd *ufds; int32_t new_size = (s->poll_entry_count + 1) * sizeof(struct pollfd); ufds = realloc(s->ufds, new_size); if (ufds == NULL) { return -ENOMEM; } s->ufds = ufds; #endif /* USE_POLL */ /* * Grow pollfd list */ res = qb_array_grow(s->poll_entries, s->poll_entry_count + 1); if (res != 0) { return res; } s->poll_entry_count += 1; install_pos = s->poll_entry_count - 1; } return install_pos; } static int32_t _poll_add_(struct qb_loop *l, enum qb_loop_priority p, int32_t fd, int32_t events, void *data, struct qb_poll_entry **pe_pt) { struct qb_poll_entry *pe; uint32_t install_pos; int32_t res = 0; struct qb_poll_source *s; if (l == NULL) { return -EINVAL; } s = (struct qb_poll_source *)l->fd_source; install_pos = _get_empty_array_position_(s); assert(qb_array_index(s->poll_entries, install_pos, (void **)&pe) == 0); pe->state = QB_POLL_ENTRY_ACTIVE; pe->install_pos = install_pos; _poll_entry_check_generate_(pe); pe->ufd.fd = fd; pe->ufd.events = events; pe->ufd.revents = 0; pe->item.user_data = data; pe->item.source = (struct qb_loop_source *)l->fd_source; pe->p = p; pe->runs = 0; res = s->driver.add(s, pe, fd, events); if (res == 0) { *pe_pt = pe; return 0; } else { pe->state = QB_POLL_ENTRY_EMPTY; return res; } } static int32_t _qb_poll_add_to_jobs_(struct qb_loop *l, struct qb_poll_entry *pe) { assert(pe->item.type == QB_LOOP_FD); qb_loop_level_item_add(&l->level[pe->p], &pe->item); pe->state = QB_POLL_ENTRY_JOBLIST; return 1; } int32_t qb_loop_poll_add(struct qb_loop * lp, enum qb_loop_priority p, int32_t fd, int32_t events, void *data, qb_loop_poll_dispatch_fn dispatch_fn) { struct qb_poll_entry *pe = NULL; int32_t size; int32_t new_size; int32_t res; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } size = ((struct qb_poll_source *)l->fd_source)->poll_entry_count; res = _poll_add_(l, p, fd, events, data, &pe); if (res != 0) { qb_util_perror(LOG_ERR, "couldn't add poll entryfor FD %d", fd); return res; } new_size = ((struct qb_poll_source *)l->fd_source)->poll_entry_count; pe->poll_dispatch_fn = dispatch_fn; pe->item.type = QB_LOOP_FD; pe->add_to_jobs = _qb_poll_add_to_jobs_; if (new_size > size) { qb_util_log(LOG_TRACE, "grown poll array to %d for FD %d", new_size, fd); } return res; } int32_t qb_loop_poll_mod(struct qb_loop * lp, enum qb_loop_priority p, int32_t fd, int32_t events, void *data, qb_loop_poll_dispatch_fn dispatch_fn) { uint32_t i; int32_t res = 0; struct qb_poll_entry *pe; struct qb_poll_source *s; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } s = (struct qb_poll_source *)l->fd_source; /* * Find file descriptor to modify events and dispatch function */ for (i = 0; i < s->poll_entry_count; i++) { assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0); if (pe->ufd.fd != fd) { continue; } if (pe->state == QB_POLL_ENTRY_DELETED || pe->check == 0) { qb_util_log(LOG_ERR, "poll_mod : can't modify entry already deleted"); return -EBADF; } pe->poll_dispatch_fn = dispatch_fn; pe->item.user_data = data; pe->p = p; if (pe->ufd.events != events) { res = s->driver.mod(s, pe, fd, events); pe->ufd.events = events; } return res; } return -EBADF; } int32_t qb_loop_poll_del(struct qb_loop * lp, int32_t fd) { int32_t i; int32_t res = 0; struct qb_poll_entry *pe; struct qb_poll_source *s; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } s = (struct qb_poll_source *)l->fd_source; for (i = 0; i < s->poll_entry_count; i++) { assert(qb_array_index(s->poll_entries, i, (void **)&pe) == 0); if (pe->ufd.fd != fd || pe->item.type != QB_LOOP_FD) { continue; } if (pe->state == QB_POLL_ENTRY_DELETED || pe->state == QB_POLL_ENTRY_EMPTY) { return 0; } if (pe->state == QB_POLL_ENTRY_JOBLIST) { qb_loop_level_item_del(&l->level[pe->p], &pe->item); } res = s->driver.del(s, pe, fd, i); _poll_entry_mark_deleted_(pe); return res; } return -EBADF; } static int32_t pipe_fds[2] = { -1, -1 }; struct qb_signal_source { struct qb_loop_source s; struct qb_list_head sig_head; sigset_t signal_superset; }; struct qb_loop_sig { struct qb_loop_item item; int32_t signal; enum qb_loop_priority p; qb_loop_signal_dispatch_fn dispatch_fn; struct qb_loop_sig *cloned_from; }; static void _handle_real_signal_(int signal_num, siginfo_t * si, void *context) { int32_t sig = signal_num; int32_t res = 0; if (pipe_fds[1] > 0) { try_again: res = write(pipe_fds[1], &sig, sizeof(int32_t)); if (res == -1 && errno == EAGAIN) { goto try_again; } else if (res != sizeof(int32_t)) { qb_util_log(LOG_ERR, "failed to write signal to pipe [%d]", res); } } qb_util_log(LOG_TRACE, "got real signal [%d] sent to pipe", sig); } static void _signal_dispatch_and_take_back_(struct qb_loop_item *item, enum qb_loop_priority p) { struct qb_loop_sig *sig = (struct qb_loop_sig *)item; int32_t res; res = sig->dispatch_fn(sig->signal, sig->item.user_data); if (res != 0) { (void)qb_loop_signal_del(sig->cloned_from->item.source->l, sig->cloned_from); } free(sig); } struct qb_loop_source * qb_loop_signals_create(struct qb_loop *l) { int32_t res = 0; struct qb_poll_entry *pe; struct qb_signal_source *s = calloc(1, sizeof(struct qb_signal_source)); if (s == NULL) { return NULL; } s->s.l = l; s->s.dispatch_and_take_back = _signal_dispatch_and_take_back_; s->s.poll = NULL; qb_list_init(&s->sig_head); sigemptyset(&s->signal_superset); if (pipe_fds[0] < 0) { res = pipe(pipe_fds); if (res == -1) { res = -errno; qb_util_perror(LOG_ERR, "Can't light pipe"); goto error_exit; } (void)qb_sys_fd_nonblock_cloexec_set(pipe_fds[0]); (void)qb_sys_fd_nonblock_cloexec_set(pipe_fds[1]); res = _poll_add_(l, QB_LOOP_HIGH, pipe_fds[0], POLLIN, NULL, &pe); if (res == 0) { pe->poll_dispatch_fn = NULL; pe->item.type = QB_LOOP_SIG; pe->add_to_jobs = _qb_signal_add_to_jobs_; } else { qb_util_perror(LOG_ERR, "Can't smoke pipe"); goto error_exit; } } return (struct qb_loop_source *)s; error_exit: errno = -res; free(s); if (pipe_fds[0] >= 0) { close(pipe_fds[0]); } if (pipe_fds[1] >= 0) { close(pipe_fds[1]); } return NULL; } void qb_loop_signals_destroy(struct qb_loop *l) { struct qb_signal_source *s = (struct qb_signal_source *)l->signal_source; struct qb_list_head *list; struct qb_list_head *n; struct qb_loop_item *item; close(pipe_fds[0]); pipe_fds[0] = -1; close(pipe_fds[1]); pipe_fds[1] = -1; qb_list_for_each_safe(list, n, &s->sig_head) { item = qb_list_entry(list, struct qb_loop_item, list); qb_list_del(&item->list); free(item); } free(l->signal_source); } static int32_t _qb_signal_add_to_jobs_(struct qb_loop *l, struct qb_poll_entry *pe) { struct qb_signal_source *s = (struct qb_signal_source *)l->signal_source; struct qb_list_head *list; struct qb_loop_sig *sig; struct qb_loop_item *item; struct qb_loop_sig *new_sig_job; int32_t the_signal; ssize_t res; int32_t jobs_added = 0; res = read(pipe_fds[0], &the_signal, sizeof(int32_t)); if (res != sizeof(int32_t)) { qb_util_perror(LOG_WARNING, "failed to read pipe"); return 0; } pe->ufd.revents = 0; qb_list_for_each(list, &s->sig_head) { item = qb_list_entry(list, struct qb_loop_item, list); sig = (struct qb_loop_sig *)item; if (sig->signal == the_signal) { new_sig_job = calloc(1, sizeof(struct qb_loop_sig)); if (new_sig_job == NULL) { return jobs_added; } memcpy(new_sig_job, sig, sizeof(struct qb_loop_sig)); qb_util_log(LOG_TRACE, "adding signal [%d] to job queue %p", the_signal, sig); new_sig_job->cloned_from = sig; qb_loop_level_item_add(&l->level[sig->p], &new_sig_job->item); jobs_added++; } } return jobs_added; } static void _adjust_sigactions_(struct qb_signal_source *s) { struct qb_loop_sig *sig; struct qb_loop_item *item; struct sigaction sa; int32_t i; int32_t needed; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = _handle_real_signal_; sigemptyset(&s->signal_superset); sigemptyset(&sa.sa_mask); /* re-set to default */ for (i = 0; i < 30; i++) { needed = QB_FALSE; qb_list_for_each_entry(item, &s->sig_head, list) { sig = (struct qb_loop_sig *)item; if (i == sig->signal) { needed = QB_TRUE; break; } } if (needed) { sigaddset(&s->signal_superset, i); sigaction(i, &sa, NULL); } else { (void)signal(i, SIG_DFL); } } } int32_t qb_loop_signal_add(qb_loop_t * lp, enum qb_loop_priority p, int32_t the_sig, void *data, qb_loop_signal_dispatch_fn dispatch_fn, qb_loop_signal_handle * handle) { struct qb_loop_sig *sig; struct qb_signal_source *s; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } if (l == NULL || dispatch_fn == NULL) { return -EINVAL; } if (p < QB_LOOP_LOW || p > QB_LOOP_HIGH) { return -EINVAL; } s = (struct qb_signal_source *)l->signal_source; sig = calloc(1, sizeof(struct qb_loop_sig)); if (sig == NULL) { return -errno; } sig->dispatch_fn = dispatch_fn; sig->p = p; sig->signal = the_sig; sig->item.user_data = data; sig->item.source = l->signal_source; sig->item.type = QB_LOOP_SIG; qb_list_init(&sig->item.list); qb_list_add_tail(&sig->item.list, &s->sig_head); if (sigismember(&s->signal_superset, the_sig) != 1) { _adjust_sigactions_(s); } if (handle) { *handle = sig; } return 0; } int32_t qb_loop_signal_mod(qb_loop_t * lp, enum qb_loop_priority p, int32_t the_sig, void *data, qb_loop_signal_dispatch_fn dispatch_fn, qb_loop_signal_handle handle) { struct qb_signal_source *s; struct qb_loop_sig *sig = (struct qb_loop_sig *)handle; struct qb_loop *l = lp; if (l == NULL) { l = qb_loop_default_get(); } if (l == NULL || dispatch_fn == NULL || handle == NULL) { return -EINVAL; } if (p < QB_LOOP_LOW || p > QB_LOOP_HIGH) { return -EINVAL; } s = (struct qb_signal_source *)l->signal_source; sig->item.user_data = data; sig->item.type = QB_LOOP_SIG; sig->dispatch_fn = dispatch_fn; sig->p = p; if (sig->signal != the_sig) { sig->signal = the_sig; _adjust_sigactions_(s); } return 0; } int32_t qb_loop_signal_del(qb_loop_t * lp, qb_loop_signal_handle handle) { struct qb_signal_source *s; struct qb_loop_sig *sig = (struct qb_loop_sig *)handle; struct qb_loop_sig *sig_clone; struct qb_loop *l = lp; struct qb_loop_item *item; if (l == NULL) { l = qb_loop_default_get(); } if (l == NULL || handle == NULL) { return -EINVAL; } s = (struct qb_signal_source *)l->signal_source; qb_list_for_each_entry(item, &l->level[sig->p].wait_head, list) { if (item->type != QB_LOOP_SIG) { continue; } sig_clone = (struct qb_loop_sig *)item; if (sig_clone->cloned_from == sig) { qb_util_log(LOG_TRACE, "deleting sig in WAITLIST"); qb_list_del(&sig_clone->item.list); free(sig_clone); break; } } qb_list_for_each_entry(item, &l->level[sig->p].job_head, list) { if (item->type != QB_LOOP_SIG) { continue; } sig_clone = (struct qb_loop_sig *)item; if (sig_clone->cloned_from == sig) { qb_loop_level_item_del(&l->level[sig->p], item); qb_util_log(LOG_TRACE, "deleting sig in JOBLIST"); break; } } qb_list_del(&sig->item.list); free(sig); _adjust_sigactions_(s); return 0; } diff --git a/lib/ringbuffer_helper.c b/lib/ringbuffer_helper.c index bff1b2c..d0c8575 100644 --- a/lib/ringbuffer_helper.c +++ b/lib/ringbuffer_helper.c @@ -1,291 +1,291 @@ /* * Copyright (C) 2010 Red Hat, Inc. * * Author: Angus Salkeld * * This file is part of libqb. * * libqb 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. * * libqb 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 libqb. If not, see . */ #include "ringbuffer_int.h" #include static int32_t my_posix_sem_timedwait(qb_ringbuffer_t * rb, int32_t ms_timeout) { struct timespec ts_timeout; int32_t res; if (ms_timeout > 0) { qb_util_timespec_from_epoch_get(&ts_timeout); qb_timespec_add_ms(&ts_timeout, ms_timeout); } sem_wait_again: if (ms_timeout > 0) { res = rpl_sem_timedwait(&rb->shared_hdr->posix_sem, &ts_timeout); } else if (ms_timeout == 0) { res = rpl_sem_trywait(&rb->shared_hdr->posix_sem); } else { res = rpl_sem_wait(&rb->shared_hdr->posix_sem); } if (res == -1) { switch (errno) { case EINTR: goto sem_wait_again; break; case EAGAIN: res = -ETIMEDOUT; break; case ETIMEDOUT: res = -errno; break; default: res = -errno; qb_util_perror(LOG_ERR, "error waiting for semaphore"); break; } } return res; } static int32_t my_posix_sem_post(qb_ringbuffer_t * rb) { if (rpl_sem_post(&rb->shared_hdr->posix_sem) < 0) { return -errno; } else { return 0; } } static ssize_t my_posix_getvalue_fn(struct qb_ringbuffer_s *rb) { int val; if (rpl_sem_getvalue(&rb->shared_hdr->posix_sem, &val) < 0) { return -errno; } else { return val; } } static int32_t my_posix_sem_destroy(qb_ringbuffer_t * rb) { if (rpl_sem_destroy(&rb->shared_hdr->posix_sem) == -1) { return -errno; } else { return 0; } } static int32_t my_posix_sem_create(struct qb_ringbuffer_s *rb, uint32_t flags) { - int32_t pshared = 0; + int32_t pshared = QB_FALSE; if (flags & QB_RB_FLAG_SHARED_PROCESS) { if ((flags & QB_RB_FLAG_CREATE) == 0) { return 0; } - pshared = 1; + pshared = QB_TRUE; } if (rpl_sem_init(&rb->shared_hdr->posix_sem, pshared, 0) == -1) { return -errno; } else { return 0; } } static int32_t my_sysv_sem_timedwait(qb_ringbuffer_t * rb, int32_t ms_timeout) { struct sembuf sops[1]; int32_t res = 0; #ifdef HAVE_SEMTIMEDOP struct timespec ts_timeout; struct timespec *ts_pt; if (ms_timeout >= 0) { /* * Note: sem_timedwait takes an absolute time where as semtimedop * takes a relative time. */ ts_timeout.tv_sec = 0; ts_timeout.tv_nsec = 0; qb_timespec_add_ms(&ts_timeout, ms_timeout); ts_pt = &ts_timeout; } else { ts_pt = NULL; } #endif /* HAVE_SEMTIMEDOP */ /* * wait for sem post. */ sops[0].sem_num = 0; sops[0].sem_op = -1; #ifdef HAVE_SEMTIMEDOP sops[0].sem_flg = 0; #else sops[0].sem_flg = IPC_NOWAIT; #endif /* HAVE_SEMTIMEDOP */ semop_again: #ifdef HAVE_SEMTIMEDOP if (semtimedop(rb->sem_id, sops, 1, ts_pt) == -1) #else if (semop(rb->sem_id, sops, 1) == -1) #endif /* HAVE_SEMTIMEDOP */ { if (errno == EINTR) { goto semop_again; } else if (errno == EAGAIN) { /* make consistent with sem_timedwait */ res = -ETIMEDOUT; } else { res = -errno; qb_util_perror(LOG_ERR, "error waiting for semaphore"); } return res; } return 0; } static int32_t my_sysv_sem_post(qb_ringbuffer_t * rb) { struct sembuf sops[1]; if ((rb->flags & QB_RB_FLAG_SHARED_PROCESS) == 0) { return 0; } sops[0].sem_num = 0; sops[0].sem_op = 1; sops[0].sem_flg = 0; semop_again: if (semop(rb->sem_id, sops, 1) == -1) { if (errno == EINTR) { goto semop_again; } else { qb_util_perror(LOG_ERR, "could not increment semaphore"); } return -errno; } return 0; } static ssize_t my_sysv_getvalue_fn(struct qb_ringbuffer_s *rb) { ssize_t res = semctl(rb->sem_id, 0, GETVAL, 0); if (res == -1) { return -errno; } return res; } static int32_t my_sysv_sem_destroy(qb_ringbuffer_t * rb) { if (semctl(rb->sem_id, 0, IPC_RMID, 0) == -1) { return -errno; } else { return 0; } } static int32_t my_sysv_sem_create(qb_ringbuffer_t * rb, uint32_t flags) { union semun options; int32_t res; key_t sem_key; sem_key = ftok(rb->shared_hdr->hdr_path, (rb->shared_hdr->word_size + 1)); if (sem_key == -1) { res = -errno; qb_util_perror(LOG_ERR, "couldn't get a sem id"); return res; } if (flags & QB_RB_FLAG_CREATE) { rb->sem_id = semget(sem_key, 1, IPC_CREAT | IPC_EXCL | 0600); if (rb->sem_id == -1) { res = -errno; qb_util_perror(LOG_ERR, "couldn't create a semaphore"); return res; } options.val = 0; res = semctl(rb->sem_id, 0, SETVAL, options); } else { rb->sem_id = semget(sem_key, 0, 0600); if (rb->sem_id == -1) { res = -errno; qb_util_perror(LOG_ERR, "couldn't get a sem id"); return res; } res = 0; } qb_util_log(LOG_DEBUG, "sem key:%d, id:%d, value:%d", (int)sem_key, rb->sem_id, semctl(rb->sem_id, 0, GETVAL, 0)); return res; } int32_t qb_rb_sem_create(struct qb_ringbuffer_s * rb, uint32_t flags) { int32_t rc; int32_t use_posix = QB_TRUE; if ((flags & QB_RB_FLAG_SHARED_PROCESS) && !(flags & QB_RB_FLAG_NO_SEMAPHORE)) { #if defined(HAVE_POSIX_PSHARED_SEMAPHORE) || \ defined(HAVE_RPL_PSHARED_SEMAPHORE) use_posix = QB_TRUE; #else #ifdef HAVE_SYSV_PSHARED_SEMAPHORE use_posix = QB_FALSE; #else return -ENOTSUP; #endif /* HAVE_SYSV_PSHARED_SEMAPHORE */ #endif /* HAVE_POSIX_PSHARED_SEMAPHORE */ } if (flags & QB_RB_FLAG_NO_SEMAPHORE) { rc = 0; rb->sem_timedwait_fn = NULL; rb->sem_post_fn = NULL; rb->sem_getvalue_fn = NULL; rb->sem_destroy_fn = NULL; } else if (use_posix) { rc = my_posix_sem_create(rb, flags); rb->sem_timedwait_fn = my_posix_sem_timedwait; rb->sem_post_fn = my_posix_sem_post; rb->sem_getvalue_fn = my_posix_getvalue_fn; rb->sem_destroy_fn = my_posix_sem_destroy; } else { rc = my_sysv_sem_create(rb, flags); rb->sem_timedwait_fn = my_sysv_sem_timedwait; rb->sem_post_fn = my_sysv_sem_post; rb->sem_getvalue_fn = my_sysv_getvalue_fn; rb->sem_destroy_fn = my_sysv_sem_destroy; } return rc; }