00001 #include <pthread.h>
00002 #include <signal.h>
00003 #include <unistd.h>
00004 #include <stdio.h>
00005 #include "tdsignals.h"
00006 #include "dsqueue.h"
00007
00008 struct td_sthreadarg_struct
00009 {
00010 unsigned int seconds;
00011 void (*shandler)(int, pthread_mutex_t *);
00012 pthread_mutex_t *mutex;
00013 };
00014
00015 typedef struct td_sthreadarg_struct td_sthreadarg_t;
00016
00017 static td_sthreadarg_t gStdarg;
00018 static Queue_t *queue = NULL;
00019 static int gArgsConsumed = 0;
00020
00021 static void *td_sigthreadfxn(void *arg)
00022 {
00023 sigset_t bsigs;
00024 sigset_t rsigs;
00025 int siggot;
00026 int err = 0;
00027 td_sthreadarg_t *stdarg = NULL;
00028 unsigned int seconds = 0;
00029 void (*shandler)(int, pthread_mutex_t*) = NULL;
00030 pthread_mutex_t *mutex = NULL;
00031 pthread_t fronttd = 0;
00032 pthread_t selftd = 0;
00033 QueueNode_t *top = NULL;
00034 QueueNode_t *thistd = NULL;
00035
00036 selftd = pthread_self();
00037
00038
00039
00040 stdarg = (td_sthreadarg_t *)arg;
00041 seconds = stdarg->seconds;
00042 shandler = stdarg->shandler;
00043 mutex = stdarg->mutex;
00044
00045
00046
00047 pthread_mutex_lock(mutex);
00048 queue_queue(queue, (void *)(&selftd));
00049 pthread_mutex_unlock(mutex);
00050
00051 gArgsConsumed = 1;
00052
00053
00054 sigfillset(&bsigs);
00055 pthread_sigmask(SIG_BLOCK, &bsigs, NULL);
00056
00057
00058 while (1)
00059 {
00060 pthread_mutex_lock(mutex);
00061 thistd = queue_find(queue, &selftd);
00062
00063 if (!thistd)
00064 {
00065
00066 pthread_mutex_unlock(mutex);
00067 return arg;
00068 }
00069
00070 top = queue_front(queue);
00071
00072 if (!top)
00073 {
00074 pthread_mutex_unlock(mutex);
00075 sched_yield();
00076 continue;
00077 }
00078
00079 fronttd = *((pthread_t *)(top->data));
00080 if (fronttd != selftd)
00081 {
00082 pthread_mutex_unlock(mutex);
00083
00084 sched_yield();
00085 }
00086 else
00087 {
00088 pthread_mutex_unlock(mutex);
00089 break;
00090 }
00091 }
00092
00093
00094 sigemptyset(&rsigs);
00095 sigaddset(&rsigs, SIGALRM);
00096
00097
00098 err = sigwait(&rsigs, &siggot);
00099
00100 if (!err)
00101 {
00102
00103 sleep(seconds);
00104
00105
00106 (*shandler)(SIGALRM, mutex);
00107 }
00108 else
00109 {
00110 fprintf(stderr, "sigwait() error in thread %lld.\n", (long long)pthread_self());
00111 }
00112
00113 return arg;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123 int td_createalarm(unsigned int seconds,
00124 void (*shandler)(int, pthread_mutex_t *),
00125 pthread_mutex_t *mutex,
00126 pthread_t *alrmtd)
00127 {
00128 int status = 0;
00129 int ret = 0;
00130 pthread_t sigthread = 0;
00131
00132
00133 if (!queue)
00134 {
00135 queue = queue_create(sizeof(pthread_t));
00136 }
00137
00138
00139 sigset_t rsigs;
00140 sigemptyset(&rsigs);
00141 sigaddset(&rsigs, SIGALRM);
00142 pthread_sigmask(SIG_BLOCK, &rsigs, NULL);
00143
00144
00145 gStdarg.seconds = seconds;
00146 gStdarg.shandler = shandler;
00147 gStdarg.mutex = mutex;
00148
00149 if((status = pthread_create(&sigthread, NULL, &td_sigthreadfxn, (void *)&gStdarg)))
00150 {
00151 fprintf(stderr, "Thread creation failed: %d\n", status);
00152 ret = 1;
00153 }
00154 else
00155 {
00156
00157
00158 pthread_kill(sigthread, SIGALRM);
00159 }
00160
00161 while (1)
00162 {
00163 pthread_mutex_lock(mutex);
00164 if (gArgsConsumed)
00165 {
00166 gArgsConsumed = 0;
00167 pthread_mutex_unlock(mutex);
00168 sched_yield();
00169 break;
00170 }
00171 else
00172 {
00173 pthread_mutex_unlock(mutex);
00174 }
00175 }
00176
00177 if (!ret && alrmtd)
00178 {
00179 pthread_mutex_lock(mutex);
00180 *alrmtd = sigthread;
00181 pthread_mutex_unlock(mutex);
00182 }
00183
00184 return ret;
00185 }
00186
00187
00188
00189
00190 void td_destroyalarm(td_alarm_t *alarm, pthread_mutex_t *mutex)
00191 {
00192 int err = 0;
00193
00194 if (alarm && *alarm)
00195 {
00196 pthread_mutex_lock(mutex);
00197 QueueNode_t *node = queue_remove(queue, alarm);
00198
00199 if (node)
00200 {
00201 queue_freenode(&node);
00202 }
00203 else
00204 {
00205 err = 1;
00206 }
00207
00208 pthread_mutex_unlock(mutex);
00209
00210 if (err)
00211 {
00212 fprintf(stderr, "Invalid alarm '%lld'\n.", (long long)*alarm);
00213 }
00214 else
00215 {
00216
00217 pthread_join(*((pthread_t *)alarm), NULL);
00218 *alarm = 0;
00219 }
00220
00221 pthread_mutex_lock(mutex);
00222
00223 if (queue_empty(queue))
00224 {
00225 queue_destroy(&queue);
00226 }
00227
00228 pthread_mutex_unlock(mutex);
00229 }
00230 }