~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/os/os0sync.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The interface to the operating system
 
3
synchronization primitives.
 
4
 
 
5
(c) 1995 Innobase Oy
 
6
 
 
7
Created 9/6/1995 Heikki Tuuri
 
8
*******************************************************/
 
9
 
 
10
#include "os0sync.h"
 
11
#ifdef UNIV_NONINL
 
12
#include "os0sync.ic"
 
13
#endif
 
14
 
 
15
#ifdef __WIN__
 
16
#include <windows.h>
 
17
#endif
 
18
 
 
19
#include "ut0mem.h"
 
20
#include "srv0start.h"
 
21
 
 
22
/* Type definition for an operating system mutex struct */
 
23
struct os_mutex_struct{
 
24
        void*           handle; /* OS handle to mutex */
 
25
        ulint           count;  /* we use this counter to check
 
26
                                that the same thread does not
 
27
                                recursively lock the mutex: we
 
28
                                do not assume that the OS mutex
 
29
                                supports recursive locking, though
 
30
                                NT seems to do that */
 
31
        UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
 
32
                                /* list of all 'slow' OS mutexes created */
 
33
};
 
34
 
 
35
/* Mutex protecting counts and the lists of OS mutexes and events */
 
36
os_mutex_t      os_sync_mutex;
 
37
ibool           os_sync_mutex_inited    = FALSE;
 
38
 
 
39
/* This is incremented by 1 in os_thread_create and decremented by 1 in
 
40
os_thread_exit */
 
41
ulint   os_thread_count         = 0;
 
42
 
 
43
/* The list of all events created */
 
44
UT_LIST_BASE_NODE_T(os_event_struct_t)  os_event_list;
 
45
 
 
46
/* The list of all OS 'slow' mutexes */
 
47
UT_LIST_BASE_NODE_T(os_mutex_str_t)     os_mutex_list;
 
48
 
 
49
ulint   os_event_count          = 0;
 
50
ulint   os_mutex_count          = 0;
 
51
ulint   os_fast_mutex_count     = 0;
 
52
 
 
53
 
 
54
/*************************************************************
 
55
Initializes global event and OS 'slow' mutex lists. */
 
56
 
 
57
void
 
58
os_sync_init(void)
 
59
/*==============*/
 
60
{
 
61
        UT_LIST_INIT(os_event_list);
 
62
        UT_LIST_INIT(os_mutex_list);
 
63
 
 
64
        os_sync_mutex = os_mutex_create(NULL);
 
65
 
 
66
        os_sync_mutex_inited = TRUE;
 
67
}
 
68
 
 
69
/*************************************************************
 
70
Frees created events and OS 'slow' mutexes. */
 
71
 
 
72
void
 
73
os_sync_free(void)
 
74
/*==============*/
 
75
{
 
76
        os_event_t      event;
 
77
        os_mutex_t      mutex;
 
78
 
 
79
        event = UT_LIST_GET_FIRST(os_event_list);
 
80
 
 
81
        while (event) {
 
82
 
 
83
                os_event_free(event);
 
84
 
 
85
                event = UT_LIST_GET_FIRST(os_event_list);
 
86
        }
 
87
 
 
88
        mutex = UT_LIST_GET_FIRST(os_mutex_list);
 
89
 
 
90
        while (mutex) {
 
91
                if (mutex == os_sync_mutex) {
 
92
                        /* Set the flag to FALSE so that we do not try to
 
93
                        reserve os_sync_mutex any more in remaining freeing
 
94
                        operations in shutdown */
 
95
                        os_sync_mutex_inited = FALSE;
 
96
                }
 
97
 
 
98
                os_mutex_free(mutex);
 
99
 
 
100
                mutex = UT_LIST_GET_FIRST(os_mutex_list);
 
101
        }
 
102
}
 
103
 
 
104
/*************************************************************
 
105
Creates an event semaphore, i.e., a semaphore which may just have two
 
106
states: signaled and nonsignaled. The created event is manual reset: it
 
107
must be reset explicitly by calling sync_os_reset_event. */
 
108
 
 
109
os_event_t
 
110
os_event_create(
 
111
/*============*/
 
112
                                /* out: the event handle */
 
113
        const char*     name)   /* in: the name of the event, if NULL
 
114
                                the event is created without a name */
 
115
{
 
116
#ifdef __WIN__
 
117
        os_event_t event;
 
118
 
 
119
        event = ut_malloc(sizeof(struct os_event_struct));
 
120
 
 
121
        event->handle = CreateEvent(NULL, /* No security attributes */
 
122
                                    TRUE, /* Manual reset */
 
123
                                    FALSE, /* Initial state nonsignaled */
 
124
                                    (LPCTSTR) name);
 
125
        if (!event->handle) {
 
126
                fprintf(stderr,
 
127
                        "InnoDB: Could not create a Windows event semaphore;"
 
128
                        " Windows error %lu\n",
 
129
                        (ulong) GetLastError());
 
130
        }
 
131
#else /* Unix */
 
132
        os_event_t      event;
 
133
 
 
134
        UT_NOT_USED(name);
 
135
 
 
136
        event = ut_malloc(sizeof(struct os_event_struct));
 
137
 
 
138
        os_fast_mutex_init(&(event->os_mutex));
 
139
 
 
140
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
 
141
        ut_a(0 == pthread_cond_init(&(event->cond_var),
 
142
                                    pthread_condattr_default));
 
143
#else
 
144
        ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
 
145
#endif
 
146
        event->is_set = FALSE;
 
147
        event->signal_count = 0;
 
148
#endif /* __WIN__ */
 
149
 
 
150
        /* Put to the list of events */
 
151
        os_mutex_enter(os_sync_mutex);
 
152
 
 
153
        UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
 
154
 
 
155
        os_event_count++;
 
156
 
 
157
        os_mutex_exit(os_sync_mutex);
 
158
 
 
159
        return(event);
 
160
}
 
161
 
 
162
#ifdef __WIN__
 
163
/*************************************************************
 
164
Creates an auto-reset event semaphore, i.e., an event which is automatically
 
165
reset when a single thread is released. Works only in Windows. */
 
166
 
 
167
os_event_t
 
168
os_event_create_auto(
 
169
/*=================*/
 
170
                                /* out: the event handle */
 
171
        const char*     name)   /* in: the name of the event, if NULL
 
172
                                the event is created without a name */
 
173
{
 
174
        os_event_t event;
 
175
 
 
176
        event = ut_malloc(sizeof(struct os_event_struct));
 
177
 
 
178
        event->handle = CreateEvent(NULL, /* No security attributes */
 
179
                                    FALSE, /* Auto-reset */
 
180
                                    FALSE, /* Initial state nonsignaled */
 
181
                                    (LPCTSTR) name);
 
182
 
 
183
        if (!event->handle) {
 
184
                fprintf(stderr,
 
185
                        "InnoDB: Could not create a Windows auto"
 
186
                        " event semaphore; Windows error %lu\n",
 
187
                        (ulong) GetLastError());
 
188
        }
 
189
 
 
190
        /* Put to the list of events */
 
191
        os_mutex_enter(os_sync_mutex);
 
192
 
 
193
        UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
 
194
 
 
195
        os_event_count++;
 
196
 
 
197
        os_mutex_exit(os_sync_mutex);
 
198
 
 
199
        return(event);
 
200
}
 
201
#endif
 
202
 
 
203
/**************************************************************
 
204
Sets an event semaphore to the signaled state: lets waiting threads
 
205
proceed. */
 
206
 
 
207
void
 
208
os_event_set(
 
209
/*=========*/
 
210
        os_event_t      event)  /* in: event to set */
 
211
{
 
212
#ifdef __WIN__
 
213
        ut_a(event);
 
214
        ut_a(SetEvent(event->handle));
 
215
#else
 
216
        ut_a(event);
 
217
 
 
218
        os_fast_mutex_lock(&(event->os_mutex));
 
219
 
 
220
        if (event->is_set) {
 
221
                /* Do nothing */
 
222
        } else {
 
223
                event->is_set = TRUE;
 
224
                event->signal_count += 1;
 
225
                ut_a(0 == pthread_cond_broadcast(&(event->cond_var)));
 
226
        }
 
227
 
 
228
        os_fast_mutex_unlock(&(event->os_mutex));
 
229
#endif
 
230
}
 
231
 
 
232
/**************************************************************
 
233
Resets an event semaphore to the nonsignaled state. Waiting threads will
 
234
stop to wait for the event. */
 
235
 
 
236
void
 
237
os_event_reset(
 
238
/*===========*/
 
239
        os_event_t      event)  /* in: event to reset */
 
240
{
 
241
#ifdef __WIN__
 
242
        ut_a(event);
 
243
 
 
244
        ut_a(ResetEvent(event->handle));
 
245
#else
 
246
        ut_a(event);
 
247
 
 
248
        os_fast_mutex_lock(&(event->os_mutex));
 
249
 
 
250
        if (!event->is_set) {
 
251
                /* Do nothing */
 
252
        } else {
 
253
                event->is_set = FALSE;
 
254
        }
 
255
 
 
256
        os_fast_mutex_unlock(&(event->os_mutex));
 
257
#endif
 
258
}
 
259
 
 
260
/**************************************************************
 
261
Frees an event object. */
 
262
 
 
263
void
 
264
os_event_free(
 
265
/*==========*/
 
266
        os_event_t      event)  /* in: event to free */
 
267
 
 
268
{
 
269
#ifdef __WIN__
 
270
        ut_a(event);
 
271
 
 
272
        ut_a(CloseHandle(event->handle));
 
273
#else
 
274
        ut_a(event);
 
275
 
 
276
        os_fast_mutex_free(&(event->os_mutex));
 
277
        ut_a(0 == pthread_cond_destroy(&(event->cond_var)));
 
278
#endif
 
279
        /* Remove from the list of events */
 
280
 
 
281
        os_mutex_enter(os_sync_mutex);
 
282
 
 
283
        UT_LIST_REMOVE(os_event_list, os_event_list, event);
 
284
 
 
285
        os_event_count--;
 
286
 
 
287
        os_mutex_exit(os_sync_mutex);
 
288
 
 
289
        ut_free(event);
 
290
}
 
291
 
 
292
/**************************************************************
 
293
Waits for an event object until it is in the signaled state. If
 
294
srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
 
295
waiting thread when the event becomes signaled (or immediately if the
 
296
event is already in the signaled state). */
 
297
 
 
298
void
 
299
os_event_wait(
 
300
/*==========*/
 
301
        os_event_t      event)  /* in: event to wait */
 
302
{
 
303
#ifdef __WIN__
 
304
        DWORD   err;
 
305
 
 
306
        ut_a(event);
 
307
 
 
308
        /* Specify an infinite time limit for waiting */
 
309
        err = WaitForSingleObject(event->handle, INFINITE);
 
310
 
 
311
        ut_a(err == WAIT_OBJECT_0);
 
312
 
 
313
        if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
 
314
                os_thread_exit(NULL);
 
315
        }
 
316
#else
 
317
        ib_longlong     old_signal_count;
 
318
 
 
319
        os_fast_mutex_lock(&(event->os_mutex));
 
320
 
 
321
        old_signal_count = event->signal_count;
 
322
 
 
323
        for (;;) {
 
324
                if (event->is_set == TRUE
 
325
                    || event->signal_count != old_signal_count) {
 
326
 
 
327
                        os_fast_mutex_unlock(&(event->os_mutex));
 
328
 
 
329
                        if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
 
330
 
 
331
                                os_thread_exit(NULL);
 
332
                        }
 
333
                        /* Ok, we may return */
 
334
 
 
335
                        return;
 
336
                }
 
337
 
 
338
                pthread_cond_wait(&(event->cond_var), &(event->os_mutex));
 
339
 
 
340
                /* Solaris manual said that spurious wakeups may occur: we
 
341
                have to check if the event really has been signaled after
 
342
                we came here to wait */
 
343
        }
 
344
#endif
 
345
}
 
346
 
 
347
/**************************************************************
 
348
Waits for an event object until it is in the signaled state or
 
349
a timeout is exceeded. In Unix the timeout is always infinite. */
 
350
 
 
351
ulint
 
352
os_event_wait_time(
 
353
/*===============*/
 
354
                                /* out: 0 if success, OS_SYNC_TIME_EXCEEDED if
 
355
                                timeout was exceeded */
 
356
        os_event_t      event,  /* in: event to wait */
 
357
        ulint           time)   /* in: timeout in microseconds, or
 
358
                                OS_SYNC_INFINITE_TIME */
 
359
{
 
360
#ifdef __WIN__
 
361
        DWORD   err;
 
362
 
 
363
        ut_a(event);
 
364
 
 
365
        if (time != OS_SYNC_INFINITE_TIME) {
 
366
                err = WaitForSingleObject(event->handle, (DWORD) time / 1000);
 
367
        } else {
 
368
                err = WaitForSingleObject(event->handle, INFINITE);
 
369
        }
 
370
 
 
371
        if (err == WAIT_OBJECT_0) {
 
372
 
 
373
                return(0);
 
374
        } else if (err == WAIT_TIMEOUT) {
 
375
 
 
376
                return(OS_SYNC_TIME_EXCEEDED);
 
377
        } else {
 
378
                ut_error;
 
379
                return(1000000); /* dummy value to eliminate compiler warn. */
 
380
        }
 
381
#else
 
382
        UT_NOT_USED(time);
 
383
 
 
384
        /* In Posix this is just an ordinary, infinite wait */
 
385
 
 
386
        os_event_wait(event);
 
387
 
 
388
        return(0);
 
389
#endif
 
390
}
 
391
 
 
392
#ifdef __WIN__
 
393
/**************************************************************
 
394
Waits for any event in an OS native event array. Returns if even a single
 
395
one is signaled or becomes signaled. */
 
396
 
 
397
ulint
 
398
os_event_wait_multiple(
 
399
/*===================*/
 
400
                                        /* out: index of the event
 
401
                                        which was signaled */
 
402
        ulint                   n,      /* in: number of events in the
 
403
                                        array */
 
404
        os_native_event_t*      native_event_array)
 
405
                                        /* in: pointer to an array of event
 
406
                                        handles */
 
407
{
 
408
        DWORD   index;
 
409
 
 
410
        ut_a(native_event_array);
 
411
        ut_a(n > 0);
 
412
 
 
413
        index = WaitForMultipleObjects((DWORD) n, native_event_array,
 
414
                                       FALSE,      /* Wait for any 1 event */
 
415
                                       INFINITE); /* Infinite wait time
 
416
                                                  limit */
 
417
        ut_a(index >= WAIT_OBJECT_0);   /* NOTE: Pointless comparision */
 
418
        ut_a(index < WAIT_OBJECT_0 + n);
 
419
 
 
420
        if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
 
421
                os_thread_exit(NULL);
 
422
        }
 
423
 
 
424
        return(index - WAIT_OBJECT_0);
 
425
}
 
426
#endif
 
427
 
 
428
/*************************************************************
 
429
Creates an operating system mutex semaphore. Because these are slow, the
 
430
mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */
 
431
 
 
432
os_mutex_t
 
433
os_mutex_create(
 
434
/*============*/
 
435
                                /* out: the mutex handle */
 
436
        const char*     name)   /* in: the name of the mutex, if NULL
 
437
                                the mutex is created without a name */
 
438
{
 
439
#ifdef __WIN__
 
440
        HANDLE          mutex;
 
441
        os_mutex_t      mutex_str;
 
442
 
 
443
        mutex = CreateMutex(NULL,       /* No security attributes */
 
444
                            FALSE,              /* Initial state: no owner */
 
445
                            (LPCTSTR) name);
 
446
        ut_a(mutex);
 
447
#else
 
448
        os_fast_mutex_t*        mutex;
 
449
        os_mutex_t              mutex_str;
 
450
 
 
451
        UT_NOT_USED(name);
 
452
 
 
453
        mutex = ut_malloc(sizeof(os_fast_mutex_t));
 
454
 
 
455
        os_fast_mutex_init(mutex);
 
456
#endif
 
457
        mutex_str = ut_malloc(sizeof(os_mutex_str_t));
 
458
 
 
459
        mutex_str->handle = mutex;
 
460
        mutex_str->count = 0;
 
461
 
 
462
        if (os_sync_mutex_inited) {
 
463
                /* When creating os_sync_mutex itself we cannot reserve it */
 
464
                os_mutex_enter(os_sync_mutex);
 
465
        }
 
466
 
 
467
        UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
 
468
 
 
469
        os_mutex_count++;
 
470
 
 
471
        if (os_sync_mutex_inited) {
 
472
                os_mutex_exit(os_sync_mutex);
 
473
        }
 
474
 
 
475
        return(mutex_str);
 
476
}
 
477
 
 
478
/**************************************************************
 
479
Acquires ownership of a mutex semaphore. */
 
480
 
 
481
void
 
482
os_mutex_enter(
 
483
/*===========*/
 
484
        os_mutex_t      mutex)  /* in: mutex to acquire */
 
485
{
 
486
#ifdef __WIN__
 
487
        DWORD   err;
 
488
 
 
489
        ut_a(mutex);
 
490
 
 
491
        /* Specify infinite time limit for waiting */
 
492
        err = WaitForSingleObject(mutex->handle, INFINITE);
 
493
 
 
494
        ut_a(err == WAIT_OBJECT_0);
 
495
 
 
496
        (mutex->count)++;
 
497
        ut_a(mutex->count == 1);
 
498
#else
 
499
        os_fast_mutex_lock(mutex->handle);
 
500
 
 
501
        (mutex->count)++;
 
502
 
 
503
        ut_a(mutex->count == 1);
 
504
#endif
 
505
}
 
506
 
 
507
/**************************************************************
 
508
Releases ownership of a mutex. */
 
509
 
 
510
void
 
511
os_mutex_exit(
 
512
/*==========*/
 
513
        os_mutex_t      mutex)  /* in: mutex to release */
 
514
{
 
515
        ut_a(mutex);
 
516
 
 
517
        ut_a(mutex->count == 1);
 
518
 
 
519
        (mutex->count)--;
 
520
#ifdef __WIN__
 
521
        ut_a(ReleaseMutex(mutex->handle));
 
522
#else
 
523
        os_fast_mutex_unlock(mutex->handle);
 
524
#endif
 
525
}
 
526
 
 
527
/**************************************************************
 
528
Frees a mutex object. */
 
529
 
 
530
void
 
531
os_mutex_free(
 
532
/*==========*/
 
533
        os_mutex_t      mutex)  /* in: mutex to free */
 
534
{
 
535
        ut_a(mutex);
 
536
 
 
537
        if (os_sync_mutex_inited) {
 
538
                os_mutex_enter(os_sync_mutex);
 
539
        }
 
540
 
 
541
        UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
 
542
 
 
543
        os_mutex_count--;
 
544
 
 
545
        if (os_sync_mutex_inited) {
 
546
                os_mutex_exit(os_sync_mutex);
 
547
        }
 
548
 
 
549
#ifdef __WIN__
 
550
        ut_a(CloseHandle(mutex->handle));
 
551
 
 
552
        ut_free(mutex);
 
553
#else
 
554
        os_fast_mutex_free(mutex->handle);
 
555
        ut_free(mutex->handle);
 
556
        ut_free(mutex);
 
557
#endif
 
558
}
 
559
 
 
560
/*************************************************************
 
561
Initializes an operating system fast mutex semaphore. */
 
562
 
 
563
void
 
564
os_fast_mutex_init(
 
565
/*===============*/
 
566
        os_fast_mutex_t*        fast_mutex)     /* in: fast mutex */
 
567
{
 
568
#ifdef __WIN__
 
569
        ut_a(fast_mutex);
 
570
 
 
571
        InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
 
572
#else
 
573
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
 
574
        ut_a(0 == pthread_mutex_init(fast_mutex, pthread_mutexattr_default));
 
575
#else
 
576
        ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
 
577
#endif
 
578
#endif
 
579
        if (os_sync_mutex_inited) {
 
580
                /* When creating os_sync_mutex itself (in Unix) we cannot
 
581
                reserve it */
 
582
 
 
583
                os_mutex_enter(os_sync_mutex);
 
584
        }
 
585
 
 
586
        os_fast_mutex_count++;
 
587
 
 
588
        if (os_sync_mutex_inited) {
 
589
                os_mutex_exit(os_sync_mutex);
 
590
        }
 
591
}
 
592
 
 
593
/**************************************************************
 
594
Acquires ownership of a fast mutex. */
 
595
 
 
596
void
 
597
os_fast_mutex_lock(
 
598
/*===============*/
 
599
        os_fast_mutex_t*        fast_mutex)     /* in: mutex to acquire */
 
600
{
 
601
#ifdef __WIN__
 
602
        EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex);
 
603
#else
 
604
        pthread_mutex_lock(fast_mutex);
 
605
#endif
 
606
}
 
607
 
 
608
/**************************************************************
 
609
Releases ownership of a fast mutex. */
 
610
 
 
611
void
 
612
os_fast_mutex_unlock(
 
613
/*=================*/
 
614
        os_fast_mutex_t*        fast_mutex)     /* in: mutex to release */
 
615
{
 
616
#ifdef __WIN__
 
617
        LeaveCriticalSection(fast_mutex);
 
618
#else
 
619
        pthread_mutex_unlock(fast_mutex);
 
620
#endif
 
621
}
 
622
 
 
623
/**************************************************************
 
624
Frees a mutex object. */
 
625
 
 
626
void
 
627
os_fast_mutex_free(
 
628
/*===============*/
 
629
        os_fast_mutex_t*        fast_mutex)     /* in: mutex to free */
 
630
{
 
631
#ifdef __WIN__
 
632
        ut_a(fast_mutex);
 
633
 
 
634
        DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
 
635
#else
 
636
        int     ret;
 
637
 
 
638
        ret = pthread_mutex_destroy(fast_mutex);
 
639
 
 
640
        if (ret != 0) {
 
641
                ut_print_timestamp(stderr);
 
642
                fprintf(stderr,
 
643
                        "  InnoDB: error: return value %lu when calling\n"
 
644
                        "InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
 
645
                fprintf(stderr,
 
646
                        "InnoDB: Byte contents of the pthread mutex at %p:\n",
 
647
                        (void*) fast_mutex);
 
648
                ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
 
649
                fprintf(stderr, "\n");
 
650
        }
 
651
#endif
 
652
        if (os_sync_mutex_inited) {
 
653
                /* When freeing the last mutexes, we have
 
654
                already freed os_sync_mutex */
 
655
 
 
656
                os_mutex_enter(os_sync_mutex);
 
657
        }
 
658
 
 
659
        os_fast_mutex_count--;
 
660
 
 
661
        if (os_sync_mutex_inited) {
 
662
                os_mutex_exit(os_sync_mutex);
 
663
        }
 
664
}