mirror of
https://salsa.debian.org/ha-team/libqb
synced 2025-12-31 10:44:13 +00:00
242 lines
5.0 KiB
C
242 lines
5.0 KiB
C
/*
|
|
* Copyright (C) 2006-2010 Red Hat, Inc.
|
|
*
|
|
* Author: Steven Dake <sdake@redhat.com>
|
|
*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "os_base.h"
|
|
|
|
#include <poll.h>
|
|
#include <signal.h>
|
|
|
|
#include "tlist.h"
|
|
|
|
#include <qb/qblist.h>
|
|
#include <qb/qbpoll.h>
|
|
#include <qb/qbtimer.h>
|
|
|
|
#define SERVER_BACKLOG 5
|
|
|
|
static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static pthread_t expiry_thread;
|
|
|
|
static pthread_attr_t thread_attr;
|
|
|
|
static struct timerlist timers_timerlist;
|
|
|
|
static int32_t sched_priority = 0;
|
|
|
|
static void (*timer_serialize_lock_fn) (void);
|
|
|
|
static void (*timer_serialize_unlock_fn) (void);
|
|
|
|
static void *prioritized_timer_thread(void *data);
|
|
|
|
extern void pthread_exit(void *) __attribute__ ((noreturn));
|
|
|
|
/*
|
|
* This thread runs at the highest priority to run system wide timers
|
|
*/
|
|
static void *prioritized_timer_thread(void *data)
|
|
{
|
|
int32_t fds;
|
|
uint64_t timeout;
|
|
|
|
#if defined(HAVE_PTHREAD_SETSCHEDPARAM) && defined(HAVE_SCHED_GET_PRIORITY_MAX)
|
|
if (sched_priority != 0) {
|
|
struct sched_param sched_param;
|
|
|
|
sched_param.sched_priority = sched_priority;
|
|
pthread_setschedparam(expiry_thread, SCHED_RR, &sched_param);
|
|
}
|
|
#endif
|
|
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
for (;;) {
|
|
timer_serialize_lock_fn();
|
|
timeout = timerlist_msec_duration_to_expire(&timers_timerlist);
|
|
if (timeout != -1 && timeout > 0xFFFFFFFF) {
|
|
timeout = 0xFFFFFFFE;
|
|
}
|
|
timer_serialize_unlock_fn();
|
|
fds = poll(NULL, 0, timeout);
|
|
if (fds < 0 && errno == EINTR) {
|
|
continue;
|
|
}
|
|
if (fds < 0) {
|
|
return NULL;
|
|
}
|
|
pthread_mutex_lock(&timer_mutex);
|
|
timer_serialize_lock_fn();
|
|
|
|
timerlist_expire(&timers_timerlist);
|
|
|
|
timer_serialize_unlock_fn();
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
}
|
|
}
|
|
|
|
static void sigusr1_handler(int32_t num)
|
|
{
|
|
#ifdef qb_SOLARIS
|
|
/* Rearm the signal facility */
|
|
signal(num, sigusr1_handler);
|
|
#endif
|
|
}
|
|
|
|
int32_t qb_timer_init(void (*serialize_lock_fn) (void),
|
|
void (*serialize_unlock_fn) (void),
|
|
int32_t sched_priority_in)
|
|
{
|
|
int32_t res;
|
|
|
|
timer_serialize_lock_fn = serialize_lock_fn;
|
|
timer_serialize_unlock_fn = serialize_unlock_fn;
|
|
sched_priority = sched_priority_in;
|
|
|
|
timerlist_init(&timers_timerlist);
|
|
|
|
signal(SIGUSR1, sigusr1_handler);
|
|
|
|
pthread_mutex_lock(&timer_mutex);
|
|
pthread_attr_init(&thread_attr);
|
|
pthread_attr_setstacksize(&thread_attr, 100000);
|
|
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
|
|
res = pthread_create(&expiry_thread, &thread_attr,
|
|
prioritized_timer_thread, NULL);
|
|
|
|
return (res);
|
|
}
|
|
|
|
int32_t qb_timer_add_absolute(uint64_t nanosec_from_epoch,
|
|
void *data,
|
|
void (*timer_fn) (void *data),
|
|
timer_handle * handle)
|
|
{
|
|
int32_t res;
|
|
int32_t unlock;
|
|
|
|
if (pthread_equal(pthread_self(), expiry_thread) != 0) {
|
|
unlock = 0;
|
|
} else {
|
|
unlock = 1;
|
|
pthread_mutex_lock(&timer_mutex);
|
|
}
|
|
|
|
res = timerlist_add_absolute(&timers_timerlist,
|
|
timer_fn,
|
|
data, nanosec_from_epoch, handle);
|
|
|
|
if (unlock) {
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
}
|
|
|
|
pthread_kill(expiry_thread, SIGUSR1);
|
|
|
|
return (res);
|
|
}
|
|
|
|
int32_t qb_timer_add_duration(uint64_t nanosec_duration,
|
|
void *data,
|
|
void (*timer_fn) (void *data),
|
|
timer_handle * handle)
|
|
{
|
|
int32_t res;
|
|
int32_t unlock;
|
|
|
|
if (pthread_equal(pthread_self(), expiry_thread) != 0) {
|
|
unlock = 0;
|
|
} else {
|
|
unlock = 1;
|
|
pthread_mutex_lock(&timer_mutex);
|
|
}
|
|
|
|
res = timerlist_add_duration(&timers_timerlist,
|
|
timer_fn, data, nanosec_duration, handle);
|
|
|
|
if (unlock) {
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
}
|
|
|
|
pthread_kill(expiry_thread, SIGUSR1);
|
|
|
|
return (res);
|
|
}
|
|
|
|
void qb_timer_delete(timer_handle th)
|
|
{
|
|
int32_t unlock;
|
|
|
|
if (th == 0) {
|
|
return;
|
|
}
|
|
|
|
if (pthread_equal(pthread_self(), expiry_thread) != 0) {
|
|
unlock = 0;
|
|
} else {
|
|
unlock = 1;
|
|
pthread_mutex_lock(&timer_mutex);
|
|
}
|
|
|
|
timerlist_del(&timers_timerlist, th);
|
|
|
|
if (unlock) {
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
}
|
|
}
|
|
|
|
void qb_timer_lock(void)
|
|
{
|
|
pthread_mutex_lock(&timer_mutex);
|
|
}
|
|
|
|
void qb_timer_unlock(void)
|
|
{
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
}
|
|
|
|
uint64_t qb_timer_time_get(void)
|
|
{
|
|
return (timerlist_nano_from_epoch());
|
|
}
|
|
|
|
uint64_t qb_timer_expire_time_get(timer_handle th)
|
|
{
|
|
int32_t unlock;
|
|
uint64_t expire;
|
|
|
|
if (th == 0) {
|
|
return (0);
|
|
}
|
|
|
|
if (pthread_equal(pthread_self(), expiry_thread) != 0) {
|
|
unlock = 0;
|
|
} else {
|
|
unlock = 1;
|
|
pthread_mutex_lock(&timer_mutex);
|
|
}
|
|
|
|
expire = timerlist_expire_time(&timers_timerlist, th);
|
|
|
|
if (unlock) {
|
|
pthread_mutex_unlock(&timer_mutex);
|
|
}
|
|
|
|
return (expire);
|
|
}
|