我试图调试问题,这是由于在我的程序中使用计时器和syslog函数。在这里,我附加了示例程序代码和终端和syslog的日志,以适当地调试它。
我不明白为什么这个程序会在一段时间后挂起。所以这里我有两个问题,1.当计时器到期时,睡眠会中断,因为它会产生SIGPROF 2。syslog在第一次试运行一段时间后就会被挂起。
代码:
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#define get_curr_date_time(date_time) \
{ \
time_t t; \
time(&t); \
char *strtime = ctime(&t); \
strncpy(date_time, strtime, strlen(strtime) - 1); \
}
#define DEBUG_INFO(p,x,arg...) \
{\
printf("%s:%d,1\n", __func__, __LINE__);\
char current_time[32] = {0}; \
printf("%s:%d,2\n", __func__, __LINE__);\
get_curr_date_time(current_time); \
printf("%s:%d,3\n", __func__, __LINE__);\
syslog(LOG_INFO,"[%s] : " p " : "#x"\n", current_time, ##arg);\
printf("%s:%d,4\n", __func__, __LINE__);\
}
char exit_flag = 0;
typedef struct _test_ctx_
{
char timer_init;
timer_t timerid;
}test_ctx;
void Timer_Handler(int sig, siginfo_t *si, void *uc)
{
printf("Timer handler is start\n");
DEBUG_INFO("timer_hang", "Timer handler is running\n");
printf("Timer handler is stop\n");
}
int InitTimer(test_ctx *tst_ctx)
{
int status = 0;
struct sigaction sa;
struct sigevent sig;
memset(&sig, 0x00, sizeof(struct sigevent));
memset(&sa, 0x00, sizeof(struct sigaction));
do
{
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = Timer_Handler;
sigemptyset(&sa.sa_mask);
if (0 != (status = sigaction(SIGPROF, &sa, NULL)))
{
printf("Fail to register SIGPROF signal for timer, ret: %d\n", status);
break;
}
sig.sigev_notify = SIGEV_SIGNAL;
sig.sigev_signo = SIGPROF;
sig.sigev_value.sival_ptr = &tst_ctx->timerid;
if (0 != (status = timer_create(CLOCK_REALTIME, &sig, &(tst_ctx->timerid))))
{
printf("Failed to create timer, ret: %d\n", status);
break;
}
//Timer inited sucessfully
tst_ctx->timer_init = 1;
}while(0);
return status;
}
void DeInitTimer(test_ctx *tst_ctx)
{
int status = 0;
if (0 != tst_ctx->timer_init)
{
//Delete timer
if (0 != (status = timer_delete(tst_ctx->timerid)))
{
printf("Fail to delete timer, ret: %d\n", status);
}
tst_ctx->timer_init = 0;
}
}
int SetTimer(test_ctx *tst_ctx)
{
int status = 0;
struct itimerspec in;
memset(&in, 0x00, sizeof(struct itimerspec));
do
{
in.it_value.tv_sec = 0;
in.it_value.tv_nsec = 1;
in.it_interval.tv_sec = 0;
in.it_interval.tv_nsec = 0;
if (0 != (status = timer_settime(tst_ctx->timerid, 0, &in, NULL)))
{
printf("Fail to set timer, ret: %d\n", status);
break;
}
}while(0);
return status;
}
void terminate_app(int sig)
{
exit_flag = 1;
printf("signal %d received exiting application\n", sig);
DEBUG_INFO("timer_hang", "signal %d received exiting application\n", sig);
}
int main(int argc, char *argv[])
{
int status = 0;
test_ctx tst_ctx;
memset(&tst_ctx, 0x00, sizeof(tst_ctx));
do
{
//Register signal handler
signal(SIGTERM, terminate_app);
signal(SIGINT, terminate_app);
//Init timer
status = InitTimer(&tst_ctx);
if (0 != status)
{
break;
}
while(0 == exit_flag)
{
printf("Setting timer\n");
DEBUG_INFO("timer_hang", "Setting timer");
//Set Timer
SetTimer(&tst_ctx);
printf("Hello!!!\n");
DEBUG_INFO("timer_hang", "Hello!!!");
printf("Say!!!\n");
sleep(5);
}
}while(0);
//De init timer
DeInitTimer(&tst_ctx);
return status;
}模板日志:
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# ./hang_issue
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,3
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
main:154,4
Say!!!
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
main:154,4
Say!!!
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
Timer_Handler:39,4
Timer handler is stop
Setting timer
main:148,1
main:148,2
main:148,3
main:148,4
Hello!!!
main:154,1
main:154,2
main:154,3
Timer handler is start
Timer_Handler:39,1
Timer_Handler:39,2
Timer_Handler:39,3
^Csignal 2 received exiting application
terminate_app:123,1
terminate_app:123,2
terminate_app:123,3
^Z
[1]+ Stopped ./hang_issue
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang#
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# killall -s 9 hang_issue
[1]+ Killed ./hang_issue
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang#
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang#系统日志消息:
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# tail -f /var/log/messages
...
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Setting timer"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Setting timer"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Setting timer"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n"
Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer"
^C
root@AHMCPU0085:/home/ravi/work/test_app/timer_hang#通过执行以下步骤,您将在linux机器上运行此测试应用程序:
# gcc -o hang_issue timer_hang.c -Wall -lrt
# ./hang_issue
... <You will get logs> ...任何帮助都将不胜感激。
你好,拉维
发布于 2015-01-22 18:52:00
正如注释中提到的,您不能在信号处理程序中使用syslog()。它不是异步信号安全,而且作为一个复杂的函数(根据需要打开和关闭到syslog的连接),难怪使用它会导致程序以奇怪和不同的方式失败。
相反,使用write()和标准输出和标准错误流。例如,
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
static void wr(int fd, const void *const ptr, const size_t len)
{
const char *p = (const char *)ptr;
const char *const q = (const char *)ptr + len;
ssize_t n;
while (p < q) {
n = write(fd, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1 || errno != EINTR)
return;
}
}
static void wrerr(const char *const string)
{
if (string != NULL)
wr(STDERR_FILENO, string, strlen(string));
}
static void wrout(const char *const string)
{
if (string != NULL)
wr(STDOUT_FILENO, string, strlen(string));
}上面,wrout()和wrerr()只接受一个字符串(比如puts(),除了它们不会自动追加换行符),也不像printf()那么有用,但是它们是异步信号安全的,并且可以安全地从信号处理程序中使用。
请记住,在使用Bash时,可以使用>out将标准输出重定向到out文件,使用2>err将标准错误重定向到err文件。输出到终端非常缓慢,因此对于任何时间,都要重定向到文件(或者更好的情况是,根本不输出额外的调试信息)。
如果确实需要从信号处理程序向syslog发送一些输出,则需要使用管道或套接字对,并从另一端读取线程或子进程,将数据发送到syslog。然后,您只需使用异步信号安全函数,就可以从信号处理程序中写入管道或套接字对(使用write())。(显然,读取和syslog数据的线程或子进程不需要使用异步信号安全函数--毕竟,它不是信号处理程序。)
让我们讨论一下超时的一般主题。
我建议不要在超时时使用正常信号。如果您需要信号,例如用于中断特定线程中的阻塞syscall,则使用实时信号(SIGRTMIN+0到SIGRTMAX-0)。
实际上,使用单独的线程来处理一组超时效果要好得多。下面是一个示例,它使用少于400行代码,允许您使用任意数量的并发超时,并为每个超时提供一个易失性标志和一个信号量,以便于使用。它使用CLOCK_MONOTONIC时钟,它不会受到跳转(UTC秒、夏时制等)的影响,但它会尝试保持实时时钟(挂钟)的滴答率:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
/* Number of timeouts to test. */
#ifndef TIMEOUT_TESTS
#define TIMEOUT_TESTS 100000
#endif
/* Seconds per timeout. */
#ifndef TIMEOUT_SECONDS
#define TIMEOUT_SECONDS 0.000000001
#endif
/* Timeout thread worker stack size; uses very few local variables. */
#define TIMEOUT_STACK_SIZE 65536
typedef struct timeout timeout;
struct timeout {
struct timeout *next;
struct timespec abstime; /* Using CLOCK_MONOTONIC clock */
sem_t elapsed; /* sem_post()ed when elapsed */
volatile int pending; /* Cleared to zero when expires */
};
static volatile int timeouts_error = -1;
static pthread_t timeouts_thread;
static pthread_mutex_t timeout_lock;
static pthread_cond_t timeout_cond; /* Uses CLOCK_MONOTONIC clock */
static timeout *volatile timeout_pending = NULL;
static void *timeouts_worker(void *unused __attribute__((unused)))
{
struct timespec now;
timeout *curr;
int err;
err = pthread_mutex_lock(&timeout_lock);
if (err) {
timeouts_error = err;
pthread_cond_signal(&timeout_cond);
return (void *)(long)err;
}
timeouts_error = 0;
pthread_cond_signal(&timeout_cond);
while (!timeouts_error) {
/* If there are no pending timeouts,
* all we need to do is wait for a condition. */
if (timeout_pending == NULL) {
pthread_cond_wait(&timeout_cond, &timeout_lock);
continue;
}
/* CLOCK_MONOTONIC is used for the timeouts. */
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
timeouts_error = errno;
pthread_mutex_unlock(&timeout_lock);
return (void *)(long)timeouts_error;
}
/* Trigger and remove all timeouts that have elapsed thus far. */
curr = timeout_pending;
while (curr != NULL &&
(curr->abstime.tv_sec < now.tv_sec ||
(curr->abstime.tv_sec == now.tv_sec &&
curr->abstime.tv_nsec <= now.tv_nsec))) {
timeout *const prev = curr;
curr = prev->next;
prev->next = NULL;
/* Mark 'prev' timeout elapsed. */
prev->pending = 0;
sem_post(&(prev->elapsed));
}
/* No more timeouts? */
if (timeout_pending == NULL)
continue;
/* Wait for the next one to elapse.
* TODO: Adjust 'now' according to previous over/undershoots,
* Say, by one tenth of previous wakeup error
* (i.e. dynamically estimating the _timedwait latency).
* This would result in much more accurate timeouts.
*/
now = timeout_pending->abstime;
pthread_cond_timedwait(&timeout_cond, &timeout_lock, &now);
}
return (void *)0L;
}
static int timeout_free(timeout *const old_timeout)
{
int err;
if (old_timeout == NULL)
return 0;
err = pthread_mutex_lock(&timeout_lock);
if (err)
return errno = err; /* We also leak memory here. */
/* Remove from timeout_pending chain. */
if (timeout_pending == old_timeout)
timeout_pending = old_timeout->next;
else {
timeout *temp = timeout_pending;
if (temp != NULL)
while (temp->next != NULL)
if (temp->next == old_timeout) {
temp->next = old_timeout->next;
break;
} else
temp = temp->next;
}
/* Unlock mutex; we no longer need to access the chain. */
pthread_mutex_unlock(&timeout_lock);
/* Poison and free the timeout structure. */
sem_destroy(&(old_timeout->elapsed));
old_timeout->next = NULL;
old_timeout->abstime.tv_sec = 0;
old_timeout->abstime.tv_nsec = 0;
old_timeout->pending = 0;
free(old_timeout);
return 0;
}
static timeout *timeout_after(const double seconds)
{
const long sec = (long)seconds;
const long nsec = (long)(1000000000.0 * (seconds - (double)sec));
struct timespec now;
timeout *new_timeout;
int err;
/* Negative time is not allowed. */
if (seconds < 0.0) {
errno = EINVAL;
return NULL;
}
/* Get current monotonic time. */
if (clock_gettime(CLOCK_MONOTONIC, &now))
return NULL;
new_timeout = malloc(sizeof *new_timeout);
if (new_timeout == NULL) {
errno = ENOMEM;
return NULL;
}
if (sem_init(&(new_timeout->elapsed), 0, 0) == -1) {
err = errno;
free(new_timeout);
errno = err;
return NULL;
}
new_timeout->next = NULL;
new_timeout->abstime.tv_sec = now.tv_sec + sec + (now.tv_nsec + nsec) / 1000000000L;
new_timeout->abstime.tv_nsec = (now.tv_nsec + nsec) % 1000000000L;
new_timeout->pending = 1;
/* Already elapsed? */
if (new_timeout->abstime.tv_sec < now.tv_sec ||
(new_timeout->abstime.tv_sec == now.tv_sec &&
new_timeout->abstime.tv_nsec <= now.tv_nsec)) {
new_timeout->next = NULL;
new_timeout->pending = 0;
sem_post(&(new_timeout->elapsed));
return new_timeout;
}
/* Get timeout lock, to add to chain. */
err = pthread_mutex_lock(&timeout_lock);
if (err) {
sem_destroy(&(new_timeout->elapsed));
free(new_timeout);
errno = err;
return NULL;
}
if (timeout_pending == NULL)
timeout_pending = new_timeout;
else
if (timeout_pending->abstime.tv_sec > new_timeout->abstime.tv_sec ||
(timeout_pending->abstime.tv_sec == new_timeout->abstime.tv_sec &&
timeout_pending->abstime.tv_nsec >= new_timeout->abstime.tv_nsec)) {
new_timeout->next = timeout_pending;
timeout_pending = new_timeout;
} else {
timeout *temp = timeout_pending;
while (temp->next != NULL &&
(temp->next->abstime.tv_sec > new_timeout->abstime.tv_sec ||
(temp->next->abstime.tv_sec == new_timeout->abstime.tv_sec &&
temp->next->abstime.tv_nsec >= new_timeout->abstime.tv_nsec)))
temp = temp->next;
new_timeout->next = temp->next;
temp->next = new_timeout;
}
/* Timeout chain manipulated; notify and unlock. */
pthread_cond_signal(&timeout_cond);
pthread_mutex_unlock(&timeout_lock);
errno = 0;
return new_timeout;
}
static int timeouts_end(void)
{
if (timeouts_error == 0) {
int err;
void *errptr;
pthread_mutex_lock(&timeout_lock);
timeouts_error = -1;
pthread_cond_signal(&timeout_cond);
pthread_mutex_unlock(&timeout_lock);
err = pthread_join(timeouts_thread, &errptr);
if (err == 0)
err = (long)errptr;
return errno = err;
} else
if (timeouts_error != -1) {
int err;
void *errptr;
err = pthread_join(timeouts_thread, &errptr);
if (err == 0)
err = (long)errptr;
else
err = timeouts_error;
return errno = err;
} else
return errno = ENOENT;
}
static int timeouts_init(void)
{
pthread_mutexattr_t lock_attrs;
pthread_condattr_t cond_attrs;
pthread_attr_t attrs;
void *errptr;
int err;
if (timeouts_error != -1)
return errno = EEXIST;
/* Initialize timeout_lock as an adaptive mutex. */
err = pthread_mutexattr_init(&lock_attrs);
if (err)
return errno = err;
err = pthread_mutexattr_settype(&lock_attrs, PTHREAD_MUTEX_ADAPTIVE_NP);
if (err)
return errno = err;
err = pthread_mutex_init(&timeout_lock, &lock_attrs);
if (err)
return errno = err;
err = pthread_mutexattr_destroy(&lock_attrs);
if (err)
return errno = err;
/* Initialize timeout_cond as a process-private monotonic clock condition variable. */
err = pthread_condattr_init(&cond_attrs);
if (err)
return errno = err;
err = pthread_condattr_setpshared(&cond_attrs, PTHREAD_PROCESS_PRIVATE);
if (err)
return errno = err;
err = pthread_condattr_setclock(&cond_attrs, CLOCK_MONOTONIC);
if (err)
return errno = err;
err = pthread_cond_init(&timeout_cond, &cond_attrs);
if (err)
return errno = err;
err = pthread_condattr_destroy(&cond_attrs);
if (err)
return errno = err;
/* Initialize the thread attributes to a 64k stack. */
err = pthread_attr_init(&attrs);
if (err)
return errno = err;
err = pthread_attr_setstacksize(&attrs, TIMEOUT_STACK_SIZE);
if (err)
return errno = err;
/* Grab the timeout lock; we'll wait on the cond later. */
err = pthread_mutex_lock(&timeout_lock);
if (err)
return errno = err;
/* Start the timeout worker thread. */
err = pthread_create(&timeouts_thread, &attrs, timeouts_worker, NULL);
if (err)
return errno = err;
pthread_attr_destroy(&attrs);
/* Wait for the worker to be ready. */
pthread_cond_wait(&timeout_cond, &timeout_lock);
/* Failed? */
if (timeouts_error != 0) {
timeouts_error = -1;
pthread_mutex_unlock(&timeout_lock);
err = pthread_join(timeouts_thread, &errptr);
if (err == 0)
err = (long)errptr;
return errno = err;
}
/* Unlock. */
pthread_mutex_unlock(&timeout_lock);
/* Success. */
return 0;
}
int main(void)
{
long i;
timeout *t;
if (timeouts_init()) {
fprintf(stderr, "Cannot initialize timeouts: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
fprintf(stderr, "Testing:\n");
fflush(stderr);
for (i = 1L; i <= TIMEOUT_TESTS; i++) {
t = timeout_after(0.000000001);
if (t == NULL) {
fprintf(stderr, "Test %ld of %ld failed: Cannot obtain a timeout: %s.\n", i, (long)TIMEOUT_TESTS, strerror(errno));
timeouts_end();
return EXIT_FAILURE;
}
printf("Timeout %ld of %ld: ", i, (long)TIMEOUT_TESTS);
fflush(stdout);
/* Wait for timeout to elapse. */
sem_wait(&(t->elapsed));
printf("Elapsed.\n");
fflush(stdout);
timeout_free(t);
}
if (timeouts_end()) {
fprintf(stderr, "Error in disarming timeouts: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
fprintf(stderr, "No errors.\n");
return EXIT_SUCCESS;
}因为我们有一个专用的超时工作线程,所以上面使用pthread_cond_timedwait()等待下一个超时发生(条件变量设置为使用CLOCK_MONOTONIC时钟源),或者一个信号(由另一个线程插入新超时)。
若要中断阻塞系统,请将pthread_t thread添加到timeout结构中,让timeout_after()将其设置为pthread_self()。安装一个实时信号(例如SIGRTMIN+0)处理程序(有一个空的主体--计算的是传递,而不是处理程序所做的事情)。最后,将pthread_kill(curr->thread, SIGRTMIN+0)添加到timeouts_worker()以提高目标线程中的信号。
上面的实现使用一个简单的排序链接列表timeout_pending来保持当前挂起的超时。这会在添加、删除和触发超时时产生O(N)行为,如果您有数百或数千个并发超时,则这是非常不理想的。将列表处理替换为二进制最小堆,以便使用大量并发超时以获得更好的性能。
此外,不需要总是向超时工作人员发出添加了新超时的信号。由于加法器持有互斥锁,因此仅当新的超时被添加为即将过去的下一个超时时,就足够了。
代码会编译,但我还没有彻底检查逻辑,因此可能会有一些bug潜伏在其中。如果你有发现,让我知道,我会设法修复它们。(不过,我很确定算法和方法本身是可行的。)
我不认为上述代码具有版权,因为它是如此直截了当,但如果有人这样做,我认为它是在公共领域,在那些没有法律概念的法域,在知识共享零许可许可。简而言之:做你想做的事,但没有保证,你不能因为任何破坏而责怪我。
有问题吗?评论?修复窃听器?
https://stackoverflow.com/questions/28060399
复制相似问题