2
* Copyright (C) 2010 Red Hat, Inc.
6
* Author: Angus Salkeld <asalkeld@redhat.com>
8
* libqb is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU Lesser General Public License as published by
10
* the Free Software Foundation, either version 2.1 of the License, or
11
* (at your option) any later version.
13
* libqb is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public License
19
* along with libqb. If not, see <http://www.gnu.org/licenses/>.
26
#include <qb/qbdefs.h>
27
#include <qb/qbutil.h>
29
struct qb_thread_lock_s {
30
qb_thread_lock_type_t type;
31
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
32
pthread_spinlock_t spinlock;
33
#endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */
34
pthread_mutex_t mutex;
38
qb_thread_lock_create(qb_thread_lock_type_t type)
40
struct qb_thread_lock_s *tl = malloc(sizeof(struct qb_thread_lock_s));
46
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
47
if (type == QB_THREAD_LOCK_SHORT) {
48
tl->type = QB_THREAD_LOCK_SHORT;
49
res = pthread_spin_init(&tl->spinlock, 1);
51
#endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */
53
tl->type = QB_THREAD_LOCK_LONG;
54
res = pthread_mutex_init(&tl->mutex, NULL);
65
qb_thread_lock(qb_thread_lock_t * tl)
68
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
69
if (tl->type == QB_THREAD_LOCK_SHORT) {
70
res = -pthread_spin_lock(&tl->spinlock);
72
#endif /* HAVE_PTHREAD_SHARED_SPIN_LOCK */
74
res = -pthread_mutex_lock(&tl->mutex);
80
qb_thread_unlock(qb_thread_lock_t * tl)
83
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
84
if (tl->type == QB_THREAD_LOCK_SHORT) {
85
res = -pthread_spin_unlock(&tl->spinlock);
89
res = -pthread_mutex_unlock(&tl->mutex);
95
qb_thread_trylock(qb_thread_lock_t * tl)
98
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
99
if (tl->type == QB_THREAD_LOCK_SHORT) {
100
res = -pthread_spin_trylock(&tl->spinlock);
104
res = -pthread_mutex_trylock(&tl->mutex);
110
qb_thread_lock_destroy(qb_thread_lock_t * tl)
113
#ifdef HAVE_PTHREAD_SHARED_SPIN_LOCK
114
if (tl->type == QB_THREAD_LOCK_SHORT) {
115
res = -pthread_spin_destroy(&tl->spinlock);
119
res = -pthread_mutex_destroy(&tl->mutex);
126
qb_timespec_add_ms(struct timespec *ts, int32_t ms)
129
ts->tv_sec += ms / 1000;
130
ts->tv_nsec += (ms % 1000) * QB_TIME_NS_IN_MSEC;
131
if (ts->tv_nsec >= 1000000000L) {
133
ts->tv_nsec = ts->tv_nsec - 1000000000L;
135
#endif /* S_SPLINT_S */
138
#ifdef HAVE_MONOTONIC_CLOCK
140
qb_util_nano_current_get(void)
142
uint64_t nano_monotonic;
145
clock_gettime(CLOCK_MONOTONIC, &ts);
147
(ts.tv_sec * QB_TIME_NS_IN_SEC) + (uint64_t) ts.tv_nsec;
148
return (nano_monotonic);
152
qb_util_nano_from_epoch_get(void)
154
uint64_t nano_monotonic;
156
#ifdef CLOCK_REALTIME_COARSE
157
clock_gettime(CLOCK_REALTIME_COARSE, &ts);
159
clock_gettime(CLOCK_REALTIME, &ts);
162
(ts.tv_sec * QB_TIME_NS_IN_SEC) + (uint64_t) ts.tv_nsec;
163
return (nano_monotonic);
167
qb_util_nano_monotonic_hz(void)
169
uint64_t nano_monotonic_hz;
172
clock_getres(CLOCK_MONOTONIC, &ts);
175
QB_TIME_NS_IN_SEC / ((ts.tv_sec * QB_TIME_NS_IN_SEC) + ts.tv_nsec);
177
return (nano_monotonic_hz);
181
qb_util_timespec_from_epoch_get(struct timespec *ts)
183
#ifdef CLOCK_REALTIME_COARSE
184
clock_gettime(CLOCK_REALTIME_COARSE, ts);
186
clock_gettime(CLOCK_REALTIME, ts);
192
qb_util_nano_current_get(void)
194
return qb_util_nano_from_epoch_get();
198
qb_util_nano_monotonic_hz(void)
200
return sysconf(_SC_CLK_TCK);
204
qb_util_timespec_from_epoch_get(struct timespec *ts)
206
struct timeval time_from_epoch;
207
gettimeofday(&time_from_epoch, 0);
210
ts->tv_sec = time_from_epoch.tv_sec;
211
ts->tv_nsec = time_from_epoch.tv_usec * QB_TIME_NS_IN_USEC;
212
#endif /* S_SPLINT_S */
216
qb_util_nano_from_epoch_get(void)
218
uint64_t nano_from_epoch;
219
struct timeval time_from_epoch;
220
gettimeofday(&time_from_epoch, 0);
222
nano_from_epoch = ((time_from_epoch.tv_sec * QB_TIME_NS_IN_SEC) +
223
(time_from_epoch.tv_usec * QB_TIME_NS_IN_USEC));
225
return (nano_from_epoch);
227
#endif /* HAVE_MONOTONIC_CLOCK */
229
struct qb_util_stopwatch {
232
uint32_t split_options;
234
uint32_t split_entries;
235
uint64_t *split_entry_list;
238
qb_util_stopwatch_t *
239
qb_util_stopwatch_create(void)
241
struct qb_util_stopwatch *sw;
242
sw = (struct qb_util_stopwatch *)calloc(1, sizeof(struct qb_util_stopwatch));
247
qb_util_stopwatch_free(qb_util_stopwatch_t * sw)
249
free(sw->split_entry_list);
254
qb_util_stopwatch_start(qb_util_stopwatch_t * sw)
256
sw->started = qb_util_nano_current_get();
258
sw->split_entries = 0;
262
qb_util_stopwatch_stop(qb_util_stopwatch_t * sw)
264
sw->stopped = qb_util_nano_current_get();
268
qb_util_stopwatch_us_elapsed_get(qb_util_stopwatch_t * sw)
270
if (sw->stopped == 0 || sw->started == 0) {
273
return ((sw->stopped - sw->started) / QB_TIME_NS_IN_USEC);
277
qb_util_stopwatch_sec_elapsed_get(qb_util_stopwatch_t * sw)
280
if (sw->stopped == 0 || sw->started == 0) {
283
e6 = qb_util_stopwatch_us_elapsed_get(sw);
284
return ((float)e6 / (float)QB_TIME_US_IN_SEC);
288
qb_util_stopwatch_split_ctl(qb_util_stopwatch_t *sw,
289
uint32_t max_splits, uint32_t options)
291
sw->split_size = max_splits;
292
sw->split_options = options;
293
sw->split_entry_list = (uint64_t *)calloc(1, sizeof (uint64_t) * max_splits);
294
if (sw->split_entry_list == NULL) {
301
qb_util_stopwatch_split(qb_util_stopwatch_t *sw)
303
uint32_t new_entry_pos;
307
if (sw->split_size == 0) {
310
if (!(sw->split_options & QB_UTIL_SW_OVERWRITE) &&
311
sw->split_entries == sw->split_size) {
314
if (sw->started == 0) {
315
qb_util_stopwatch_start(sw);
317
new_entry_pos = sw->split_entries % (sw->split_size);
318
sw->split_entry_list[new_entry_pos] = qb_util_nano_current_get();
321
time_start = sw->split_entry_list[new_entry_pos];
322
if (sw->split_entries == 1) {
324
time_end = sw->started;
325
} else if (new_entry_pos == 0) {
327
time_end = sw->split_entry_list[sw->split_size - 1];
329
time_end = sw->split_entry_list[(new_entry_pos - 1) % sw->split_size];
331
return (time_start - time_end) / QB_TIME_NS_IN_USEC;
335
qb_util_stopwatch_split_last(qb_util_stopwatch_t *sw)
337
if (sw->split_entries) {
338
return sw->split_entries - 1;
340
return sw->split_entries;
344
qb_util_stopwatch_time_split_get(qb_util_stopwatch_t *sw,
345
uint32_t receint, uint32_t older)
350
if (sw->started == 0 ||
351
receint >= sw->split_entries ||
352
older >= sw->split_entries ||
356
if (sw->split_options & QB_UTIL_SW_OVERWRITE &&
357
(receint < (sw->split_entries - sw->split_size) ||
358
older < (sw->split_entries - sw->split_size))) {
362
time_start = sw->split_entry_list[receint % (sw->split_size)];
363
if (older == receint) {
364
time_end = sw->started;
366
time_end = sw->split_entry_list[older % (sw->split_size)];
368
return (time_start - time_end) / QB_TIME_NS_IN_USEC;