/*
Copyright (C) MINZKN.COM
All rights reserved.
Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>
*/
#if !defined(_ISOC99_SOURCE)
# define _ISOC99_SOURCE (1L)
#endif
#if !defined(_GNU_SOURCE)
# define _GNU_SOURCE (1L)
#endif
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#define def_thread_signal_test_case (1) /* 0=control by main, 1=control by thread */
#define def_thread_signal_interval (1000) /* msec */
typedef struct thread_context_ts {
pthread_mutex_t m_lock;
int m_overrun_count;
}__thread_context_t;
#define thread_context_t __thread_context_t
typedef void *(*th_t)(void *);
static void *thread_common(void *s_argument, const char *s_caller_name, size_t s_caller_line);
static void *thread1(void *s_argument);
static void *thread2(void *s_argument);
static void *thread3(void *s_argument);
static void *thread4(void *s_argument);
static void thread5_signal_handler(int s_signal);
static void *thread5_use_signal(void *s_argument);
int main(int s_argc, char **s_argv);
#if def_thread_signal_test_case == (1)
typedef struct thread_control_info_ts {
th_t *m_thread_table;
int m_thread_count;
pthread_t *m_thread_id;
thread_context_t *m_thread_context;
}__thread_control_info_t;
#define thread_control_info_t __thread_control_info_t
static void *control_thread(void *s_argument);
static void *control_thread(void *s_argument)
{
thread_control_info_t *s_control = (thread_control_info_t *)s_argument;
int s_thread_index;
int s_tick, s_count;
(void)fprintf(stdout, "control thread begin\n");
do {
sigset_t s_sigmask;
/* int sigemptyset(sigset_t *set); */
(void)sigemptyset((sigset_t *)(&s_sigmask));
/* int sigaddset(sigset_t *set, int signum); */
(void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
/* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
(void)pthread_sigmask(SIG_BLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
}while(0);
for(s_tick = 0;;s_tick++) {
s_thread_index = s_tick % s_control->m_thread_count;
(void)fprintf(stdout, "---- tick=%d, thread_index=%d\n", s_tick, s_thread_index);
for(s_count = 0;s_count < (s_thread_index + 1);s_count++) {
/* int pthread_mutex_lock(pthread_mutex_t *mutex) */
(void)pthread_mutex_lock((pthread_mutex_t *)(&s_control->m_thread_context[s_thread_index].m_lock));
++s_control->m_thread_context[s_thread_index].m_overrun_count;
/* int pthread_kill(pthread_t thread, int sig); */
(void)pthread_kill(s_control->m_thread_id[s_thread_index], SIGINT);
/* int pthread_unmutex_lock(pthread_mutex_t *mutex) */
(void)pthread_mutex_unlock((pthread_mutex_t *)(&s_control->m_thread_context[s_thread_index].m_lock));
#if 0L
(void)fprintf(stdout, "pthread_kill[%d] done.\n", s_thread_index);
#endif
}
#if def_thread_signal_interval > (0)
usleep(def_thread_signal_interval * 1000);
#endif
}
(void)fprintf(stdout, "control thread end\n");
return((void *)0);
}
#endif
static void *thread_common(void *s_argument, const char *s_caller_name, size_t s_caller_line)
{
thread_context_t *s_thread_context = (thread_context_t *)s_argument;
int s_overrun_index, s_overrun_count;
sigset_t s_sigmask;
int s_signal;
int s_count;
/* int sigemptyset(sigset_t *set); */
(void)sigemptyset((sigset_t *)(&s_sigmask));
/* int sigaddset(sigset_t *set, int signum); */
(void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
/* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
(void)pthread_sigmask(SIG_BLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
for(s_count = 0;;) {
/* int sigwait(const sigset_t *set, int *sig); */
(void)sigwait((const sigset_t *)(&s_sigmask), (int *)(&s_signal));
/* int pthread_mutex_lock(pthread_mutex_t *mutex) */
(void)pthread_mutex_lock((pthread_mutex_t *)(&s_thread_context->m_lock));
s_overrun_count = s_thread_context->m_overrun_count;
s_thread_context->m_overrun_count -= s_overrun_count;
/* int pthread_mutex_unlock(pthread_mutex_t *mutex) */
(void)pthread_mutex_unlock((pthread_mutex_t *)(&s_thread_context->m_lock));
for(s_overrun_index = 0;s_overrun_index < s_overrun_count;s_overrun_index++) {
(void)fprintf(stdout, "\t[%d/%d]: \x1b[1;33m%s\x1b[0m:%lu[%d] sig=%d\n", s_overrun_index + 1, s_overrun_count, s_caller_name, (unsigned long)s_caller_line, s_count, s_signal);
}
++s_count;
}
return((void *)0);
}
static void *thread1(void *s_argument)
{
return(thread_common(s_argument, __func__, __LINE__));
}
static void *thread2(void *s_argument)
{
return(thread_common(s_argument, __func__, __LINE__));
}
static void *thread3(void *s_argument)
{
return(thread_common(s_argument, __func__, __LINE__));
}
static void *thread4(void *s_argument)
{
return(thread_common(s_argument, __func__, __LINE__));
}
static void thread5_signal_handler(int s_signal)
{
(void)fprintf(stderr, "\t*** func=\"%s\", signal=%d\n", __func__, s_signal);
}
static void *thread5_use_signal(void *s_argument)
{
thread_context_t *s_thread_context = (thread_context_t *)s_argument;
int s_overrun_index, s_overrun_count;
sigset_t s_sigmask;
struct sigaction s_sigaction;
int s_count;
/* int sigemptyset(sigset_t *set); */
(void)sigemptyset((sigset_t *)(&s_sigmask));
/* int sigaddset(sigset_t *set, int signum); */
(void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
/* int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); */
(void)memset((void *)(&s_sigaction), 0, sizeof(s_sigaction));
s_sigaction.sa_handler = &thread5_signal_handler;
(void)sigaction(SIGINT, (const struct sigaction *)(&s_sigaction), (struct sigaction *)0);
(void)sigaction(SIGUSR1, (const struct sigaction *)(&s_sigaction), (struct sigaction *)0);
(void)sigaction(SIGUSR2, (const struct sigaction *)(&s_sigaction), (struct sigaction *)0);
/* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
(void)pthread_sigmask(SIG_UNBLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
for(s_count = 0;;) {
/* int pthread_mutex_lock(pthread_mutex_t *mutex) */
(void)pthread_mutex_lock((pthread_mutex_t *)(&s_thread_context->m_lock));
s_overrun_count = s_thread_context->m_overrun_count;
s_thread_context->m_overrun_count -= s_overrun_count;
/* int pthread_mutex_unlock(pthread_mutex_t *mutex) */
(void)pthread_mutex_unlock((pthread_mutex_t *)(&s_thread_context->m_lock));
if(s_overrun_count <= 0) {
usleep(10 * 1000); /* load balance */
continue;
}
for(s_overrun_index = 0;s_overrun_index < s_overrun_count;s_overrun_index++) {
(void)fprintf(stdout, "\t[%d/%d]: \x1b[1;33m%s\x1b[0m:%lu[%d]\n", s_overrun_index + 1, s_overrun_count, __func__, (unsigned long)__LINE__, s_count);
}
++s_count;
}
return((void *)0);
}
int main(int s_argc, char **s_argv)
{
th_t s_thread_table[] = {
&thread1,
&thread2,
&thread3,
&thread4,
&thread5_use_signal,
(th_t)0
};
int s_thread_index, s_thread_count;
pthread_t s_thread_id[sizeof(s_thread_table) / sizeof(void *)];
thread_context_t s_thread_context[sizeof(s_thread_table) / sizeof(void *)];
#if def_thread_signal_test_case == (0)
(void)fprintf(stdout, "thread signal test begin. [Quit to Ctrl+\\]\n");
#elif def_thread_signal_test_case == (1)
(void)fprintf(stdout, "thread signal test begin. [Quit to Ctrl+C]\n");
#endif
#if def_thread_signal_test_case == (0)
do {
sigset_t s_sigmask;
/* int sigemptyset(sigset_t *set); */
(void)sigemptyset((sigset_t *)(&s_sigmask));
/* int sigaddset(sigset_t *set, int signum); */
(void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
(void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
/* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
(void)pthread_sigmask(SIG_BLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
}while(0);
#endif
for(s_thread_index = 0;s_thread_table[s_thread_index] != ((th_t)0);s_thread_index++) {
/* int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); */
(void)pthread_mutex_init((pthread_mutex_t *)(&s_thread_context[s_thread_index].m_lock), (const pthread_mutexattr_t *)0);
s_thread_context[s_thread_index].m_overrun_count = 0;
/* int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); */
if(pthread_create((pthread_t *)(&s_thread_id[s_thread_index]), (const pthread_attr_t *)0, s_thread_table[s_thread_index], (void *)(&s_thread_context[s_thread_index])) == 0) {
(void)pthread_detach(s_thread_id[s_thread_index]);
(void)fprintf(stdout, "pthread_create[%d] done.\n", s_thread_index);
}
}
s_thread_count = s_thread_index;
#if def_thread_signal_test_case == (0)
do {
int s_tick, s_count;
for(s_tick = 0;;s_tick++) {
s_thread_index = s_tick % s_thread_count;
(void)fprintf(stdout, "---- tick=%d, thread_index=%d\n", s_tick, s_thread_index);
for(s_count = 0;s_count < (s_thread_index + 1);s_count++) {
/* int pthread_mutex_lock(pthread_mutex_t *mutex) */
(void)pthread_mutex_lock((pthread_mutex_t *)(&s_thread_context[s_thread_index].m_lock));
++s_thread_context[s_thread_index].m_overrun_count;
/* int pthread_kill(pthread_t thread, int sig); */
(void)pthread_kill(s_thread_id[s_thread_index], SIGINT);
/* int pthread_unmutex_lock(pthread_mutex_t *mutex) */
(void)pthread_mutex_unlock((pthread_mutex_t *)(&s_thread_context[s_thread_index].m_lock));
#if 0L
(void)fprintf(stdout, "pthread_kill[%d] done.\n", s_thread_index);
#endif
}
#if def_thread_signal_interval > (0)
usleep(def_thread_signal_interval * 1000);
#endif
}
}while(0);
#elif def_thread_signal_test_case == (1)
do {
thread_control_info_t s_control_local;
thread_control_info_t *s_control;
pthread_t s_control_thread_id;
s_control = (thread_control_info_t *)memset((void *)(&s_control_local), 0, sizeof(s_control_local));
s_control->m_thread_table = (th_t *)(&s_thread_table[0]);
s_control->m_thread_count = s_thread_count;
s_control->m_thread_id = (pthread_t *)(&s_thread_id[0]);
s_control->m_thread_context = (thread_context_t *)(&s_thread_context[0]);
if(pthread_create((pthread_t *)(&s_control_thread_id), (const pthread_attr_t *)0, control_thread, (void *)s_control) == 0) {
(void)fprintf(stdout, "control thread join...\n");
/* int pthread_join(pthread_t thread, void **retval); */
(void)pthread_join(s_control_thread_id, (void **)0);
}
}while(0);
#endif
(void)fprintf(stdout, "thread signal test end.\n");
return(EXIT_SUCCESS);
}
/* vim: set expandtab: */
/* End of source */