13
13
along with this program; if not, write to the Free Software
14
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "mysys_priv.h"
16
/* To avoid problems with alarms in debug code, we disable DBUG here */
17
#define FORCE_DBUG_OFF
18
#include <my_global.h>
18
20
#if !defined(DONT_USE_THR_ALARM)
20
22
#include <my_pthread.h>
21
23
#include <signal.h>
22
24
#include <my_sys.h>
23
#include <mystrings/m_string.h>
24
26
#include <queues.h>
25
27
#include "thr_alarm.h"
28
30
#include <sys/select.h> /* AIX needs this for fd_set */
31
#if TIME_WITH_SYS_TIME
32
# include <sys/time.h>
36
# include <sys/time.h>
44
34
#define ETIME ETIMEDOUT
47
uint32_t thr_client_alarm;
37
uint thr_client_alarm;
48
38
static int alarm_aborted=1; /* No alarm thread */
49
bool thr_alarm_inited= 0;
50
volatile bool alarm_thread_running= 0;
39
my_bool thr_alarm_inited= 0;
40
volatile my_bool alarm_thread_running= 0;
51
41
time_t next_alarm_expire_time= ~ (time_t) 0;
52
static RETSIGTYPE process_alarm_part2(int sig);
42
static sig_handler process_alarm_part2(int sig);
54
44
static pthread_mutex_t LOCK_alarm;
55
45
static pthread_cond_t COND_alarm;
56
46
static sigset_t full_signal_set;
57
47
static QUEUE alarm_queue;
58
static uint32_t max_used_alarms=0;
48
static uint max_used_alarms=0;
59
49
pthread_t alarm_thread;
61
51
#ifdef USE_ALARM_THREAD
65
55
#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
68
static RETSIGTYPE thread_alarm(int sig __attribute__((unused)));
58
static sig_handler thread_alarm(int sig __attribute__((unused)));
70
static int compare_uint32_t(void *not_used __attribute__((unused)),
71
unsigned char *a_ptr,unsigned char* b_ptr)
60
static int compare_ulong(void *not_used __attribute__((unused)),
61
uchar *a_ptr,uchar* b_ptr)
73
uint32_t a=*((uint32_t*) a_ptr),b= *((uint32_t*) b_ptr);
63
ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
74
64
return (a < b) ? -1 : (a == b) ? 0 : 1;
77
void init_thr_alarm(uint32_t max_alarms)
67
void init_thr_alarm(uint max_alarms)
70
DBUG_ENTER("init_thr_alarm");
81
72
next_alarm_expire_time= ~ (time_t) 0;
82
73
init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
83
compare_uint32_t,NULL);
84
75
sigfillset(&full_signal_set); /* Neaded to block signals */
85
76
pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST);
86
77
pthread_cond_init(&COND_alarm,NULL);
106
97
pthread_attr_setstacksize(&thr_attr,8196);
108
99
my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
109
pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL);
110
pthread_attr_destroy(&thr_attr);
100
VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL));
101
VOID(pthread_attr_destroy(&thr_attr));
112
103
#elif defined(USE_ONE_SIGNAL_HAND)
113
104
pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
120
111
my_sigset(THR_SERVER_ALARM, process_alarm);
121
112
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
122
113
#endif /* USE_ALARM_THREAD */
127
void resize_thr_alarm(uint32_t max_alarms)
118
void resize_thr_alarm(uint max_alarms)
129
120
pthread_mutex_lock(&LOCK_alarm);
156
147
when the alarm has been given
159
bool thr_alarm(thr_alarm_t *alrm, uint32_t sec, ALARM *alarm_data)
150
my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
162
153
#ifndef USE_ONE_SIGNAL_HAND
163
154
sigset_t old_mask;
166
157
struct st_my_thread_var *current_my_thread_var= my_thread_var;
158
DBUG_ENTER("thr_alarm");
159
DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
169
162
#ifndef USE_ONE_SIGNAL_HAND
172
165
pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
173
166
if (alarm_aborted > 0)
174
167
{ /* No signal thread */
168
DBUG_PRINT("info", ("alarm aborted"));
175
169
*alrm= 0; /* No alarm */
176
170
pthread_mutex_unlock(&LOCK_alarm);
177
171
#ifndef USE_ONE_SIGNAL_HAND
178
172
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
182
176
if (alarm_aborted < 0)
183
177
sec= 1; /* Abort mode */
187
181
if (alarm_queue.elements == alarm_queue.max_elements)
183
DBUG_PRINT("info", ("alarm queue full"));
189
184
fprintf(stderr,"Warning: thr_alarm queue is full\n");
190
185
*alrm= 0; /* No alarm */
191
186
pthread_mutex_unlock(&LOCK_alarm);
192
187
#ifndef USE_ONE_SIGNAL_HAND
193
188
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
197
192
max_used_alarms=alarm_queue.elements+1;
199
reschedule= (uint32_t) next_alarm_expire_time > (uint32_t) now + sec;
194
reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
202
197
if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
199
DBUG_PRINT("info", ("failed my_malloc()"));
204
200
*alrm= 0; /* No alarm */
205
201
pthread_mutex_unlock(&LOCK_alarm);
206
202
#ifndef USE_ONE_SIGNAL_HAND
207
203
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
211
207
alarm_data->malloced=1;
216
212
alarm_data->alarmed=0;
217
213
alarm_data->thread= current_my_thread_var->pthread_self;
218
214
alarm_data->thread_id= current_my_thread_var->id;
219
queue_insert(&alarm_queue,(unsigned char*) alarm_data);
215
queue_insert(&alarm_queue,(uchar*) alarm_data);
221
217
/* Reschedule alarm if the current one has more than sec left */
220
DBUG_PRINT("info", ("reschedule"));
224
221
if (pthread_equal(pthread_self(),alarm_thread))
226
223
alarm(sec); /* purecov: inspected */
248
245
#ifndef USE_ONE_SIGNAL_HAND
249
246
sigset_t old_mask;
249
DBUG_ENTER("thr_end_alarm");
253
251
#ifndef USE_ONE_SIGNAL_HAND
254
252
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
256
254
pthread_mutex_lock(&LOCK_alarm);
258
alarm_data= (ALARM*) ((unsigned char*) *alarmed - offsetof(ALARM,alarmed));
256
alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
259
257
for (i=0 ; i < alarm_queue.elements ; i++)
261
259
if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
263
261
queue_remove(&alarm_queue,i),MYF(0);
264
262
if (alarm_data->malloced)
265
free((unsigned char*) alarm_data);
263
my_free((uchar*) alarm_data,MYF(0));
270
assert(!*alarmed || found == 1);
270
DBUG_ASSERT(!*alarmed || found == 1);
274
274
fprintf(stderr,"Warning: Didn't find alarm 0x%lx in queue of %d alarms\n",
275
275
(long) *alarmed, alarm_queue.elements);
276
DBUG_PRINT("warning",("Didn't find alarm 0x%lx in queue\n",
277
279
pthread_mutex_unlock(&LOCK_alarm);
278
280
#ifndef USE_ONE_SIGNAL_HAND
279
281
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
292
RETSIGTYPE process_alarm(int sig __attribute__((unused)))
294
sig_handler process_alarm(int sig __attribute__((unused)))
294
296
sigset_t old_mask;
298
This must be first as we can't call DBUG inside an alarm for a normal thread
296
301
if (thd_lib_detected == THD_LIB_LT &&
297
302
!pthread_equal(pthread_self(),alarm_thread))
299
304
#if defined(MAIN) && !defined(__bsdi__)
300
305
printf("thread_alarm in process_alarm\n"); fflush(stdout);
302
#ifndef HAVE_BSD_SIGNALS
307
#ifdef DONT_REMEMBER_SIGNAL
303
308
my_sigset(thr_client_alarm, process_alarm); /* int. thread system calls */
314
We have to do do the handling of the alarm in a sub function,
315
because otherwise we would get problems with two threads calling
316
DBUG_... functions at the same time (as two threads may call
317
process_alarm() at the same time
308
320
#ifndef USE_ALARM_THREAD
309
321
pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
310
322
pthread_mutex_lock(&LOCK_alarm);
312
324
process_alarm_part2(sig);
313
325
#ifndef USE_ALARM_THREAD
314
#if !defined(HAVE_BSD_SIGNALS) && !defined(USE_ONE_SIGNAL_HAND)
326
#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
315
327
my_sigset(THR_SERVER_ALARM,process_alarm);
317
329
pthread_mutex_unlock(&LOCK_alarm);
324
static RETSIGTYPE process_alarm_part2(int sig __attribute__((unused)))
336
static sig_handler process_alarm_part2(int sig __attribute__((unused)))
326
338
ALARM *alarm_data;
339
DBUG_ENTER("process_alarm");
340
DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
328
342
#if defined(MAIN)
329
343
printf("process_alarm\n"); fflush(stdout);
358
uint32_t now=(uint32_t) my_time(0);
359
uint32_t next=now+10-(now%10);
372
ulong now=(ulong) my_time(0);
373
ulong next=now+10-(now%10);
360
374
while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
362
376
alarm_data->alarmed=1; /* Info to thread */
377
DBUG_PRINT("info",("sending signal to waiting thread"));
363
378
if (pthread_equal(alarm_data->thread,alarm_thread) ||
364
379
pthread_kill(alarm_data->thread, thr_client_alarm))
411
426
- All new alarms will be rescheduled to one second
414
void end_thr_alarm(bool free_structures)
429
void end_thr_alarm(my_bool free_structures)
431
DBUG_ENTER("end_thr_alarm");
416
432
if (alarm_aborted != 1) /* If memory not freed */
418
434
pthread_mutex_lock(&LOCK_alarm);
435
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
419
436
alarm_aborted= -1; /* mark aborted */
420
437
if (alarm_queue.elements || (alarm_thread_running && free_structures))
429
446
struct timespec abstime;
431
assert(!alarm_queue.elements);
448
DBUG_ASSERT(!alarm_queue.elements);
433
450
/* Wait until alarm thread dies */
434
451
set_timespec(abstime, 10); /* Wait up to 10 seconds */
471
488
ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
472
489
tmp->expire_time=0;
473
queue_insert(&alarm_queue,(unsigned char*) tmp);
490
queue_insert(&alarm_queue,(uchar*) tmp);
474
491
reschedule_alarms();
486
503
info->max_used_alarms= max_used_alarms;
487
504
if ((info->active_alarms= alarm_queue.elements))
489
uint32_t now=(uint32_t) my_time(0);
506
ulong now=(ulong) my_time(0);
491
508
ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
492
509
time_diff= (long) (alarm_data->expire_time - now);
493
info->next_alarm_time= (uint32_t) (time_diff < 0 ? 0 : time_diff);
510
info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff);
495
512
pthread_mutex_unlock(&LOCK_alarm);
504
static RETSIGTYPE thread_alarm(int sig)
521
static sig_handler thread_alarm(int sig)
507
524
printf("thread_alarm\n"); fflush(stdout);
509
#ifndef HAVE_BSD_SIGNALS
526
#ifdef DONT_REMEMBER_SIGNAL
510
527
my_sigset(sig,thread_alarm); /* int. thread system calls */
570
587
process_alarm(0);
572
memset(&alarm_thread, 0, sizeof(alarm_thread)); /* For easy debugging */
589
bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
573
590
alarm_thread_running= 0;
574
591
pthread_cond_signal(&COND_alarm);
575
592
pthread_mutex_unlock(&LOCK_alarm);
591
608
static pthread_cond_t COND_thread_count;
592
609
static pthread_mutex_t LOCK_thread_count;
593
static uint32_t thread_count;
610
static uint thread_count;
596
613
typedef int * fd_set_ptr;
637
654
if (wait_time == 7)
638
655
{ /* Simulate alarm-miss */
640
uint32_t max_connection=fileno(stdin);
657
uint max_connection=fileno(stdin);
641
658
FD_ZERO(&readFDs);
642
659
FD_SET(max_connection,&readFDs);
679
696
pthread_mutex_lock(&LOCK_thread_count);
681
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
698
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
682
699
pthread_mutex_unlock(&LOCK_thread_count);
683
free((unsigned char*) arg);
687
704
#ifdef USE_ONE_SIGNAL_HAND
688
static RETSIGTYPE print_signal_warning(int sig)
705
static sig_handler print_signal_warning(int sig)
690
707
printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
692
#ifndef HAVE_BSD_SIGNALS
709
#ifdef DONT_REMEMBER_SIGNAL
693
710
my_sigset(sig,print_signal_warning); /* int. thread system calls */
695
712
if (sig == SIGALRM)
707
724
pthread_detach_this_thread();
708
725
init_thr_alarm(10); /* Setup alarm handler */
709
726
pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
710
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
727
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
711
728
pthread_mutex_unlock(&LOCK_thread_count);
713
730
sigemptyset(&set); /* Catch all signals */
727
744
printf("server alarm: %d thread alarm: %d\n",
728
745
THR_SERVER_ALARM, thr_client_alarm);
746
DBUG_PRINT("info",("Starting signal and alarm handling thread"));
731
749
while ((error=my_sigwait(&set,&sig)) == EINTR)
794
816
sigemptyset(&set);
795
817
sigaddset(&set, thr_client_alarm);
796
pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0);
818
VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
799
821
pthread_attr_init(&thr_attr);
802
824
pthread_attr_setstacksize(&thr_attr,65536L);
804
826
/* Start signal thread and wait for it to start */
805
pthread_mutex_lock(&LOCK_thread_count);
827
VOID(pthread_mutex_lock(&LOCK_thread_count));
806
828
pthread_create(&tid,&thr_attr,signal_hand,NULL);
807
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
808
pthread_mutex_unlock(&LOCK_thread_count);
829
VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
830
VOID(pthread_mutex_unlock(&LOCK_thread_count));
831
DBUG_PRINT("info",("signal thread created"));
810
833
thr_setconcurrency(3);
811
834
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
832
855
alarm_info.next_alarm_time);
833
856
while (thread_count)
835
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
858
VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
836
859
if (thread_count == 1)
838
861
printf("Calling end_thr_alarm. This should cancel the last thread\n");