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"
32
34
#define ETIME ETIMEDOUT
35
uint32_t thr_client_alarm;
37
uint thr_client_alarm;
36
38
static int alarm_aborted=1; /* No alarm thread */
37
39
bool thr_alarm_inited= 0;
38
40
volatile bool alarm_thread_running= 0;
39
41
time_t next_alarm_expire_time= ~ (time_t) 0;
40
static RETSIGTYPE process_alarm_part2(int sig);
42
static sig_handler process_alarm_part2(int sig);
42
44
static pthread_mutex_t LOCK_alarm;
43
45
static pthread_cond_t COND_alarm;
44
46
static sigset_t full_signal_set;
45
47
static QUEUE alarm_queue;
46
static uint32_t max_used_alarms=0;
48
static uint max_used_alarms=0;
47
49
pthread_t alarm_thread;
49
51
#ifdef USE_ALARM_THREAD
53
55
#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
56
static RETSIGTYPE thread_alarm(int sig __attribute__((unused)));
58
static sig_handler thread_alarm(int sig __attribute__((unused)));
58
static int compare_uint32_t(void *not_used __attribute__((unused)),
59
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)
61
uint32_t a=*((uint32_t*) a_ptr),b= *((uint32_t*) b_ptr);
63
ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
62
64
return (a < b) ? -1 : (a == b) ? 0 : 1;
65
void init_thr_alarm(uint32_t max_alarms)
67
void init_thr_alarm(uint max_alarms)
70
DBUG_ENTER("init_thr_alarm");
69
72
next_alarm_expire_time= ~ (time_t) 0;
70
73
init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
71
compare_uint32_t,NULL);
72
75
sigfillset(&full_signal_set); /* Neaded to block signals */
73
76
pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST);
74
77
pthread_cond_init(&COND_alarm,NULL);
94
97
pthread_attr_setstacksize(&thr_attr,8196);
96
99
my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
97
pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL);
98
pthread_attr_destroy(&thr_attr);
100
VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL));
101
VOID(pthread_attr_destroy(&thr_attr));
100
103
#elif defined(USE_ONE_SIGNAL_HAND)
101
104
pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
108
111
my_sigset(THR_SERVER_ALARM, process_alarm);
109
112
pthread_sigmask(SIG_UNBLOCK, &s, NULL);
110
113
#endif /* USE_ALARM_THREAD */
115
void resize_thr_alarm(uint32_t max_alarms)
118
void resize_thr_alarm(uint max_alarms)
117
120
pthread_mutex_lock(&LOCK_alarm);
144
147
when the alarm has been given
147
bool thr_alarm(thr_alarm_t *alrm, uint32_t sec, ALARM *alarm_data)
150
bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
150
153
#ifndef USE_ONE_SIGNAL_HAND
154
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));
157
162
#ifndef USE_ONE_SIGNAL_HAND
160
165
pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
161
166
if (alarm_aborted > 0)
162
167
{ /* No signal thread */
168
DBUG_PRINT("info", ("alarm aborted"));
163
169
*alrm= 0; /* No alarm */
164
170
pthread_mutex_unlock(&LOCK_alarm);
165
171
#ifndef USE_ONE_SIGNAL_HAND
166
172
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
170
176
if (alarm_aborted < 0)
171
177
sec= 1; /* Abort mode */
175
181
if (alarm_queue.elements == alarm_queue.max_elements)
183
DBUG_PRINT("info", ("alarm queue full"));
177
184
fprintf(stderr,"Warning: thr_alarm queue is full\n");
178
185
*alrm= 0; /* No alarm */
179
186
pthread_mutex_unlock(&LOCK_alarm);
180
187
#ifndef USE_ONE_SIGNAL_HAND
181
188
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
185
192
max_used_alarms=alarm_queue.elements+1;
187
reschedule= (uint32_t) next_alarm_expire_time > (uint32_t) now + sec;
194
reschedule= (ulong) next_alarm_expire_time > (ulong) now + sec;
190
197
if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
199
DBUG_PRINT("info", ("failed my_malloc()"));
192
200
*alrm= 0; /* No alarm */
193
201
pthread_mutex_unlock(&LOCK_alarm);
194
202
#ifndef USE_ONE_SIGNAL_HAND
195
203
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
199
207
alarm_data->malloced=1;
204
212
alarm_data->alarmed=0;
205
213
alarm_data->thread= current_my_thread_var->pthread_self;
206
214
alarm_data->thread_id= current_my_thread_var->id;
207
queue_insert(&alarm_queue,(unsigned char*) alarm_data);
215
queue_insert(&alarm_queue,(uchar*) alarm_data);
209
217
/* Reschedule alarm if the current one has more than sec left */
220
DBUG_PRINT("info", ("reschedule"));
212
221
if (pthread_equal(pthread_self(),alarm_thread))
214
223
alarm(sec); /* purecov: inspected */
236
245
#ifndef USE_ONE_SIGNAL_HAND
237
246
sigset_t old_mask;
249
DBUG_ENTER("thr_end_alarm");
241
251
#ifndef USE_ONE_SIGNAL_HAND
242
252
pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
244
254
pthread_mutex_lock(&LOCK_alarm);
246
alarm_data= (ALARM*) ((unsigned char*) *alarmed - offsetof(ALARM,alarmed));
256
alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
247
257
for (i=0 ; i < alarm_queue.elements ; i++)
249
259
if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
251
261
queue_remove(&alarm_queue,i),MYF(0);
252
262
if (alarm_data->malloced)
253
free((unsigned char*) alarm_data);
263
my_free((uchar*) alarm_data,MYF(0));
258
assert(!*alarmed || found == 1);
270
DBUG_ASSERT(!*alarmed || found == 1);
262
274
fprintf(stderr,"Warning: Didn't find alarm 0x%lx in queue of %d alarms\n",
263
275
(long) *alarmed, alarm_queue.elements);
276
DBUG_PRINT("warning",("Didn't find alarm 0x%lx in queue\n",
265
279
pthread_mutex_unlock(&LOCK_alarm);
266
280
#ifndef USE_ONE_SIGNAL_HAND
267
281
pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
280
RETSIGTYPE process_alarm(int sig __attribute__((unused)))
294
sig_handler process_alarm(int sig __attribute__((unused)))
282
296
sigset_t old_mask;
298
This must be first as we can't call DBUG inside an alarm for a normal thread
284
301
if (thd_lib_detected == THD_LIB_LT &&
285
302
!pthread_equal(pthread_self(),alarm_thread))
287
304
#if defined(MAIN) && !defined(__bsdi__)
288
305
printf("thread_alarm in process_alarm\n"); fflush(stdout);
290
#ifndef HAVE_BSD_SIGNALS
307
#ifdef DONT_REMEMBER_SIGNAL
291
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
296
320
#ifndef USE_ALARM_THREAD
297
321
pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
298
322
pthread_mutex_lock(&LOCK_alarm);
300
324
process_alarm_part2(sig);
301
325
#ifndef USE_ALARM_THREAD
302
#if !defined(HAVE_BSD_SIGNALS) && !defined(USE_ONE_SIGNAL_HAND)
326
#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
303
327
my_sigset(THR_SERVER_ALARM,process_alarm);
305
329
pthread_mutex_unlock(&LOCK_alarm);
312
static RETSIGTYPE process_alarm_part2(int sig __attribute__((unused)))
336
static sig_handler process_alarm_part2(int sig __attribute__((unused)))
314
338
ALARM *alarm_data;
339
DBUG_ENTER("process_alarm");
340
DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
316
342
#if defined(MAIN)
317
343
printf("process_alarm\n"); fflush(stdout);
346
uint32_t now=(uint32_t) my_time(0);
347
uint32_t next=now+10-(now%10);
372
ulong now=(ulong) my_time(0);
373
ulong next=now+10-(now%10);
348
374
while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
350
376
alarm_data->alarmed=1; /* Info to thread */
377
DBUG_PRINT("info",("sending signal to waiting thread"));
351
378
if (pthread_equal(alarm_data->thread,alarm_thread) ||
352
379
pthread_kill(alarm_data->thread, thr_client_alarm))
402
429
void end_thr_alarm(bool free_structures)
431
DBUG_ENTER("end_thr_alarm");
404
432
if (alarm_aborted != 1) /* If memory not freed */
406
434
pthread_mutex_lock(&LOCK_alarm);
435
DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
407
436
alarm_aborted= -1; /* mark aborted */
408
437
if (alarm_queue.elements || (alarm_thread_running && free_structures))
417
446
struct timespec abstime;
419
assert(!alarm_queue.elements);
448
DBUG_ASSERT(!alarm_queue.elements);
421
450
/* Wait until alarm thread dies */
422
451
set_timespec(abstime, 10); /* Wait up to 10 seconds */
459
488
ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
460
489
tmp->expire_time=0;
461
queue_insert(&alarm_queue,(unsigned char*) tmp);
490
queue_insert(&alarm_queue,(uchar*) tmp);
462
491
reschedule_alarms();
474
503
info->max_used_alarms= max_used_alarms;
475
504
if ((info->active_alarms= alarm_queue.elements))
477
uint32_t now=(uint32_t) my_time(0);
506
ulong now=(ulong) my_time(0);
479
508
ALARM *alarm_data= (ALARM*) queue_top(&alarm_queue);
480
509
time_diff= (long) (alarm_data->expire_time - now);
481
info->next_alarm_time= (uint32_t) (time_diff < 0 ? 0 : time_diff);
510
info->next_alarm_time= (ulong) (time_diff < 0 ? 0 : time_diff);
483
512
pthread_mutex_unlock(&LOCK_alarm);
492
static RETSIGTYPE thread_alarm(int sig)
521
static sig_handler thread_alarm(int sig)
495
524
printf("thread_alarm\n"); fflush(stdout);
497
#ifndef HAVE_BSD_SIGNALS
526
#ifdef DONT_REMEMBER_SIGNAL
498
527
my_sigset(sig,thread_alarm); /* int. thread system calls */
558
587
process_alarm(0);
560
memset(&alarm_thread, 0, sizeof(alarm_thread)); /* For easy debugging */
589
bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
561
590
alarm_thread_running= 0;
562
591
pthread_cond_signal(&COND_alarm);
563
592
pthread_mutex_unlock(&LOCK_alarm);
579
608
static pthread_cond_t COND_thread_count;
580
609
static pthread_mutex_t LOCK_thread_count;
581
static uint32_t thread_count;
610
static uint thread_count;
584
613
typedef int * fd_set_ptr;
625
654
if (wait_time == 7)
626
655
{ /* Simulate alarm-miss */
628
uint32_t max_connection=fileno(stdin);
657
uint max_connection=fileno(stdin);
629
658
FD_ZERO(&readFDs);
630
659
FD_SET(max_connection,&readFDs);
667
696
pthread_mutex_lock(&LOCK_thread_count);
669
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
698
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
670
699
pthread_mutex_unlock(&LOCK_thread_count);
671
free((unsigned char*) arg);
675
704
#ifdef USE_ONE_SIGNAL_HAND
676
static RETSIGTYPE print_signal_warning(int sig)
705
static sig_handler print_signal_warning(int sig)
678
707
printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
680
#ifndef HAVE_BSD_SIGNALS
709
#ifdef DONT_REMEMBER_SIGNAL
681
710
my_sigset(sig,print_signal_warning); /* int. thread system calls */
683
712
if (sig == SIGALRM)
695
724
pthread_detach_this_thread();
696
725
init_thr_alarm(10); /* Setup alarm handler */
697
726
pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
698
pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */
727
VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
699
728
pthread_mutex_unlock(&LOCK_thread_count);
701
730
sigemptyset(&set); /* Catch all signals */
715
744
printf("server alarm: %d thread alarm: %d\n",
716
745
THR_SERVER_ALARM, thr_client_alarm);
746
DBUG_PRINT("info",("Starting signal and alarm handling thread"));
719
749
while ((error=my_sigwait(&set,&sig)) == EINTR)
782
816
sigemptyset(&set);
783
817
sigaddset(&set, thr_client_alarm);
784
pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0);
818
VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
787
821
pthread_attr_init(&thr_attr);
790
824
pthread_attr_setstacksize(&thr_attr,65536L);
792
826
/* Start signal thread and wait for it to start */
793
pthread_mutex_lock(&LOCK_thread_count);
827
VOID(pthread_mutex_lock(&LOCK_thread_count));
794
828
pthread_create(&tid,&thr_attr,signal_hand,NULL);
795
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
796
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"));
798
833
thr_setconcurrency(3);
799
834
pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
820
855
alarm_info.next_alarm_time);
821
856
while (thread_count)
823
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
858
VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
824
859
if (thread_count == 1)
826
861
printf("Calling end_thr_alarm. This should cancel the last thread\n");