Drizzled Public API Documentation

os0sync.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "univ.i"
27 
28 #include <errno.h>
29 
30 #include "os0sync.h"
31 #ifdef UNIV_NONINL
32 #include "os0sync.ic"
33 #endif
34 
35 #ifdef __WIN__
36 #include <windows.h>
37 #endif
38 
39 #include "ut0mem.h"
40 #include "srv0start.h"
41 #include "srv0srv.h"
42 #include "ha_prototypes.h"
43 
44 /* Type definition for an operating system mutex struct */
47  void* handle;
48  ulint count;
54  UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list;
55  /* list of all 'slow' OS mutexes created */
56 };
57 
59 UNIV_INTERN os_mutex_t os_sync_mutex;
61 static ibool os_sync_mutex_inited = FALSE;
63 static ibool os_sync_free_called = FALSE;
64 
67 UNIV_INTERN ulint os_thread_count = 0;
68 
70 static UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list;
71 
73 static UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list;
74 
75 UNIV_INTERN ulint os_event_count = 0;
76 UNIV_INTERN ulint os_mutex_count = 0;
77 UNIV_INTERN ulint os_fast_mutex_count = 0;
78 
79 /* The number of microsecnds in a second. */
80 static const ulint MICROSECS_IN_A_SECOND = 1000000;
81 
82 /* Because a mutex is embedded inside an event and there is an
83 event embedded inside a mutex, on free, this generates a recursive call.
84 This version of the free event function doesn't acquire the global lock */
85 static void os_event_free_internal(os_event_t event);
86 
87 /* On Windows (Vista and later), load function pointers for condition
88 variable handling. Those functions are not available in prior versions,
89 so we have to use them via runtime loading, as long as we support XP. */
90 static void os_cond_module_init(void);
91 
92 #ifdef __WIN__
93 /* Prototypes and function pointers for condition variable functions */
94 typedef VOID (WINAPI* InitializeConditionVariableProc)
95  (PCONDITION_VARIABLE ConditionVariable);
96 static InitializeConditionVariableProc initialize_condition_variable;
97 
98 typedef BOOL (WINAPI* SleepConditionVariableCSProc)
99  (PCONDITION_VARIABLE ConditionVariable,
100  PCRITICAL_SECTION CriticalSection,
101  DWORD dwMilliseconds);
102 static SleepConditionVariableCSProc sleep_condition_variable;
103 
104 typedef VOID (WINAPI* WakeAllConditionVariableProc)
105  (PCONDITION_VARIABLE ConditionVariable);
106 static WakeAllConditionVariableProc wake_all_condition_variable;
107 
108 typedef VOID (WINAPI* WakeConditionVariableProc)
109  (PCONDITION_VARIABLE ConditionVariable);
110 static WakeConditionVariableProc wake_condition_variable;
111 #endif
112 
113 /*********************************************************/
115 UNIV_INLINE
116 void
117 os_cond_init(
118 /*=========*/
119  os_cond_t* cond)
120 {
121  ut_a(cond);
122 
123 #ifdef __WIN__
124  ut_a(initialize_condition_variable != NULL);
125  initialize_condition_variable(cond);
126 #else
127  ut_a(pthread_cond_init(cond, NULL) == 0);
128 #endif
129 }
130 
131 /*********************************************************/
134 UNIV_INLINE
135 ibool
136 os_cond_wait_timed(
137 /*===============*/
138  os_cond_t* cond,
139  os_fast_mutex_t* mutex,
140 #ifndef __WIN__
141  const struct timespec* abstime
142 #else
143  DWORD time_in_ms
145 #endif /* !__WIN__ */
146 )
147 {
148 #ifdef __WIN__
149  BOOL ret;
150  DWORD err;
151 
152  ut_a(sleep_condition_variable != NULL);
153 
154  ret = sleep_condition_variable(cond, mutex, time_in_ms);
155 
156  if (!ret) {
157  err = GetLastError();
158  /* From http://msdn.microsoft.com/en-us/library/ms686301%28VS.85%29.aspx,
159  "Condition variables are subject to spurious wakeups
160  (those not associated with an explicit wake) and stolen wakeups
161  (another thread manages to run before the woken thread)."
162  Check for both types of timeouts.
163  Conditions are checked by the caller.*/
164  if ((err == WAIT_TIMEOUT) || (err == ERROR_TIMEOUT)) {
165  return(TRUE);
166  }
167  }
168 
169  ut_a(ret);
170 
171  return(FALSE);
172 #else
173  int ret;
174 
175  ret = pthread_cond_timedwait(cond, mutex, abstime);
176 
177  switch (ret) {
178  case 0:
179  case ETIMEDOUT:
180  /* We play it safe by checking for EINTR even though
181  according to the POSIX documentation it can't return EINTR. */
182  case EINTR:
183  break;
184 
185  default:
186  fprintf(stderr, " InnoDB: pthread_cond_timedwait() returned: "
187  "%d: abstime={%lu,%lu}\n",
188  ret, (ulong) abstime->tv_sec, (ulong) abstime->tv_nsec);
189  ut_error;
190  }
191 
192  return(ret == ETIMEDOUT);
193 #endif
194 }
195 /*********************************************************/
197 UNIV_INLINE
198 void
199 os_cond_wait(
200 /*=========*/
201  os_cond_t* cond,
202  os_fast_mutex_t* mutex)
203 {
204  ut_a(cond);
205  ut_a(mutex);
206 
207 #ifdef __WIN__
208  ut_a(sleep_condition_variable != NULL);
209  ut_a(sleep_condition_variable(cond, mutex, INFINITE));
210 #else
211  ut_a(pthread_cond_wait(cond, mutex) == 0);
212 #endif
213 }
214 
215 /*********************************************************/
217 UNIV_INLINE
218 void
219 os_cond_broadcast(
220 /*==============*/
221  os_cond_t* cond)
222 {
223  ut_a(cond);
224 
225 #ifdef __WIN__
226  ut_a(wake_all_condition_variable != NULL);
227  wake_all_condition_variable(cond);
228 #else
229  ut_a(pthread_cond_broadcast(cond) == 0);
230 #endif
231 }
232 
233 /*********************************************************/
235 UNIV_INLINE
236 void
237 os_cond_signal(
238 /*==========*/
239  os_cond_t* cond)
240 {
241  ut_a(cond);
242 
243 #ifdef __WIN__
244  ut_a(wake_condition_variable != NULL);
245  wake_condition_variable(cond);
246 #else
247  ut_a(pthread_cond_signal(cond) == 0);
248 #endif
249 }
250 
251 /*********************************************************/
253 UNIV_INLINE
254 void
255 os_cond_destroy(
256 /*============*/
257  os_cond_t* cond)
258 {
259 #ifdef __WIN__
260  /* Do nothing */
261 #else
262  ut_a(pthread_cond_destroy(cond) == 0);
263 #endif
264 }
265 
266 /*********************************************************/
270 static
271 void
272 os_cond_module_init(void)
273 /*=====================*/
274 {
275 #ifdef __WIN__
276  HMODULE h_dll;
277 
278  if (!srv_use_native_conditions)
279  return;
280 
281  h_dll = GetModuleHandle("kernel32");
282 
283  initialize_condition_variable = (InitializeConditionVariableProc)
284  GetProcAddress(h_dll, "InitializeConditionVariable");
285  sleep_condition_variable = (SleepConditionVariableCSProc)
286  GetProcAddress(h_dll, "SleepConditionVariableCS");
287  wake_all_condition_variable = (WakeAllConditionVariableProc)
288  GetProcAddress(h_dll, "WakeAllConditionVariable");
289  wake_condition_variable = (WakeConditionVariableProc)
290  GetProcAddress(h_dll, "WakeConditionVariable");
291 
292  /* When using native condition variables, check function pointers */
293  ut_a(initialize_condition_variable);
294  ut_a(sleep_condition_variable);
295  ut_a(wake_all_condition_variable);
296  ut_a(wake_condition_variable);
297 #endif
298 }
299 
300 /*********************************************************/
302 UNIV_INTERN
303 void
305 /*==============*/
306 {
307  UT_LIST_INIT(os_event_list);
308  UT_LIST_INIT(os_mutex_list);
309 
310  os_sync_mutex = NULL;
311  os_sync_mutex_inited = FALSE;
312 
313  /* Now for Windows only */
314  os_cond_module_init();
315 
316  os_sync_mutex = os_mutex_create();
317 
318  os_sync_mutex_inited = TRUE;
319 }
320 
321 /*********************************************************/
323 UNIV_INTERN
324 void
326 /*==============*/
327 {
329  os_mutex_t mutex;
330 
331  os_sync_free_called = TRUE;
332  event = UT_LIST_GET_FIRST(os_event_list);
333 
334  while (event) {
335 
336  os_event_free(event);
337 
338  event = UT_LIST_GET_FIRST(os_event_list);
339  }
340 
341  mutex = UT_LIST_GET_FIRST(os_mutex_list);
342 
343  while (mutex) {
344  if (mutex == os_sync_mutex) {
345  /* Set the flag to FALSE so that we do not try to
346  reserve os_sync_mutex any more in remaining freeing
347  operations in shutdown */
348  os_sync_mutex_inited = FALSE;
349  }
350 
351  os_mutex_free(mutex);
352 
353  mutex = UT_LIST_GET_FIRST(os_mutex_list);
354  }
355  os_sync_free_called = FALSE;
356 }
357 
358 /*********************************************************/
363 UNIV_INTERN
366 /*============*/
367  const char* name)
369 {
371 
372 #ifdef __WIN__
373  if(!srv_use_native_conditions) {
374 
375  event = ut_malloc(sizeof(struct os_event_struct));
376 
377  event->handle = CreateEvent(NULL,
378  TRUE,
379  FALSE,
380  (LPCTSTR) name);
381  if (!event->handle) {
382  fprintf(stderr,
383  "InnoDB: Could not create a Windows event"
384  " semaphore; Windows error %lu\n",
385  (ulong) GetLastError());
386  }
387  } else /* Windows with condition variables */
388 #endif
389 
390  {
391  UT_NOT_USED(name);
392 
393  event = static_cast<os_event_struct*>(ut_malloc(sizeof(struct os_event_struct)));
394 
395  os_fast_mutex_init(&(event->os_mutex));
396 
397  os_cond_init(&(event->cond_var));
398 
399  event->is_set = FALSE;
400 
401  /* We return this value in os_event_reset(), which can then be
402  be used to pass to the os_event_wait_low(). The value of zero
403  is reserved in os_event_wait_low() for the case when the
404  caller does not want to pass any signal_count value. To
405  distinguish between the two cases we initialize signal_count
406  to 1 here. */
407  event->signal_count = 1;
408  }
409 
410  /* The os_sync_mutex can be NULL because during startup an event
411  can be created [ because it's embedded in the mutex/rwlock ] before
412  this module has been initialized */
413  if (os_sync_mutex != NULL) {
414  os_mutex_enter(os_sync_mutex);
415  }
416 
417  /* Put to the list of events */
418  UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
419 
420  os_event_count++;
421 
422  if (os_sync_mutex != NULL) {
423  os_mutex_exit(os_sync_mutex);
424  }
425 
426  return(event);
427 }
428 
429 /**********************************************************/
432 UNIV_INTERN
433 void
435 /*=========*/
436  os_event_t event)
437 {
438  ut_a(event);
439 
440 #ifdef __WIN__
441  if (!srv_use_native_conditions) {
442  ut_a(SetEvent(event->handle));
443  return;
444  }
445 #endif
446 
447  ut_a(event);
448 
449  os_fast_mutex_lock(&(event->os_mutex));
450 
451  if (event->is_set) {
452  /* Do nothing */
453  } else {
454  event->is_set = TRUE;
455  event->signal_count += 1;
456  os_cond_broadcast(&(event->cond_var));
457  }
458 
459  os_fast_mutex_unlock(&(event->os_mutex));
460 }
461 
462 /**********************************************************/
470 UNIV_INTERN
471 ib_int64_t
473 /*===========*/
474  os_event_t event)
475 {
476  ib_int64_t ret = 0;
477 
478  ut_a(event);
479 
480 #ifdef __WIN__
481  if(!srv_use_native_conditions) {
482  ut_a(ResetEvent(event->handle));
483  return(0);
484  }
485 #endif
486 
487  os_fast_mutex_lock(&(event->os_mutex));
488 
489  if (!event->is_set) {
490  /* Do nothing */
491  } else {
492  event->is_set = FALSE;
493  }
494  ret = event->signal_count;
495 
496  os_fast_mutex_unlock(&(event->os_mutex));
497  return(ret);
498 }
499 
500 /**********************************************************/
502 static
503 void
504 os_event_free_internal(
505 /*===================*/
506  os_event_t event)
507 {
508 #ifdef __WIN__
509  if(!srv_use_native_conditions) {
510  ut_a(event);
511  ut_a(CloseHandle(event->handle));
512  } else
513 #endif
514  {
515  ut_a(event);
516 
517  /* This is to avoid freeing the mutex twice */
518  os_fast_mutex_free(&(event->os_mutex));
519 
520  os_cond_destroy(&(event->cond_var));
521  }
522 
523  /* Remove from the list of events */
524  UT_LIST_REMOVE(os_event_list, os_event_list, event);
525 
526  os_event_count--;
527 
528  ut_free(event);
529 }
530 
531 /**********************************************************/
533 UNIV_INTERN
534 void
536 /*==========*/
537  os_event_t event)
539 {
540  ut_a(event);
541 #ifdef __WIN__
542  if(!srv_use_native_conditions){
543  ut_a(CloseHandle(event->handle));
544  } else /*Windows with condition variables */
545 #endif
546  {
547  os_fast_mutex_free(&(event->os_mutex));
548 
549  os_cond_destroy(&(event->cond_var));
550  }
551 
552  /* Remove from the list of events */
553  os_mutex_enter(os_sync_mutex);
554 
555  UT_LIST_REMOVE(os_event_list, os_event_list, event);
556 
557  os_event_count--;
558 
559  os_mutex_exit(os_sync_mutex);
560 
561  ut_free(event);
562 }
563 
564 /**********************************************************/
584 UNIV_INTERN
585 void
587 /*==============*/
588  os_event_t event,
589  ib_int64_t reset_sig_count)
592 {
593  ib_int64_t old_signal_count;
594 
595 #ifdef __WIN__
596  if(!srv_use_native_conditions) {
597  DWORD err;
598 
599  ut_a(event);
600 
601  UT_NOT_USED(reset_sig_count);
602 
603  /* Specify an infinite wait */
604  err = WaitForSingleObject(event->handle, INFINITE);
605 
606  ut_a(err == WAIT_OBJECT_0);
607 
609  os_thread_exit(NULL);
610  }
611  return;
612  }
613 #endif
614 
615  os_fast_mutex_lock(&(event->os_mutex));
616 
617  if (reset_sig_count) {
618  old_signal_count = reset_sig_count;
619  } else {
620  old_signal_count = event->signal_count;
621  }
622 
623  for (;;) {
624  if (event->is_set == TRUE
625  || event->signal_count != old_signal_count) {
626 
627  os_fast_mutex_unlock(&(event->os_mutex));
628 
630 
631  os_thread_exit(NULL);
632  }
633  /* Ok, we may return */
634 
635  return;
636  }
637 
638  os_cond_wait(&(event->cond_var), &(event->os_mutex));
639 
640  /* Solaris manual said that spurious wakeups may occur: we
641  have to check if the event really has been signaled after
642  we came here to wait */
643  }
644 }
645 
646 /**********************************************************/
650 UNIV_INTERN
651 ulint
653 /*===================*/
654  os_event_t event,
655  ulint time_in_usec,
658  ib_int64_t reset_sig_count)
662 {
663  ibool timed_out = FALSE;
664  ib_int64_t old_signal_count;
665 
666 #ifdef __WIN__
667  DWORD time_in_ms;
668 
669  if (!srv_use_native_conditions) {
670  DWORD err;
671 
672  ut_a(event);
673 
674  if (time_in_usec != OS_SYNC_INFINITE_TIME) {
675  time_in_ms = time_in_usec / 1000;
676  err = WaitForSingleObject(event->handle, time_in_ms);
677  } else {
678  err = WaitForSingleObject(event->handle, INFINITE);
679  }
680 
681  if (err == WAIT_OBJECT_0) {
682  return(0);
683  } else if ((err == WAIT_TIMEOUT) || (err == ERROR_TIMEOUT)) {
684  return(OS_SYNC_TIME_EXCEEDED);
685  }
686 
687  ut_error;
688  /* Dummy value to eliminate compiler warning. */
689  return(42);
690  } else {
691  ut_a(sleep_condition_variable != NULL);
692 
693  if (time_in_usec != OS_SYNC_INFINITE_TIME) {
694  time_in_ms = time_in_usec / 1000;
695  } else {
696  time_in_ms = INFINITE;
697  }
698  }
699 #else
700  struct timespec abstime;
701 
702  if (time_in_usec != OS_SYNC_INFINITE_TIME) {
703  struct timeval tv;
704  int ret;
705  ulint sec;
706  ulint usec;
707 
708  ret = ut_usectime(&sec, &usec);
709  ut_a(ret == 0);
710 
711  tv.tv_sec = sec;
712  tv.tv_usec = usec;
713 
714  tv.tv_usec += time_in_usec;
715 
716  if ((ulint) tv.tv_usec >= MICROSECS_IN_A_SECOND) {
717  tv.tv_sec += time_in_usec / MICROSECS_IN_A_SECOND;
718  tv.tv_usec %= MICROSECS_IN_A_SECOND;
719  }
720 
721  abstime.tv_sec = tv.tv_sec;
722  abstime.tv_nsec = tv.tv_usec * 1000;
723  } else {
724  abstime.tv_nsec = 999999999;
725  abstime.tv_sec = (time_t) ULINT_MAX;
726  }
727 
728  ut_a(abstime.tv_nsec <= 999999999);
729 
730 #endif /* __WIN__ */
731 
732  os_fast_mutex_lock(&event->os_mutex);
733 
734  if (reset_sig_count) {
735  old_signal_count = reset_sig_count;
736  } else {
737  old_signal_count = event->signal_count;
738  }
739 
740  do {
741  if (event->is_set == TRUE
742  || event->signal_count != old_signal_count) {
743 
744  break;
745  }
746 
747  timed_out = os_cond_wait_timed(
748  &event->cond_var, &event->os_mutex,
749 #ifndef __WIN__
750  &abstime
751 #else
752  time_in_ms
753 #endif /* !__WIN__ */
754  );
755 
756  } while (!timed_out);
757 
759 
761 
762  os_thread_exit(NULL);
763  }
764 
765  return(timed_out ? OS_SYNC_TIME_EXCEEDED : 0);
766 }
767 
768 /*********************************************************/
772 UNIV_INTERN
775 /*=================*/
776 {
777  os_fast_mutex_t* mutex;
778  os_mutex_t mutex_str;
779 
780  mutex = static_cast<os_fast_mutex_t*>(ut_malloc(sizeof(os_fast_mutex_t)));
781 
782  os_fast_mutex_init(mutex);
783  mutex_str = static_cast<os_mutex_t>(ut_malloc(sizeof(os_mutex_str_t)));
784 
785  mutex_str->handle = mutex;
786  mutex_str->count = 0;
787  mutex_str->event = os_event_create(NULL);
788 
789  if (UNIV_LIKELY(os_sync_mutex_inited)) {
790  /* When creating os_sync_mutex itself we cannot reserve it */
791  os_mutex_enter(os_sync_mutex);
792  }
793 
794  UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
795 
796  os_mutex_count++;
797 
798  if (UNIV_LIKELY(os_sync_mutex_inited)) {
799  os_mutex_exit(os_sync_mutex);
800  }
801 
802  return(mutex_str);
803 }
804 
805 /**********************************************************/
807 UNIV_INTERN
808 void
810 /*===========*/
811  os_mutex_t mutex)
812 {
813  os_fast_mutex_lock(static_cast<os_fast_mutex_t *>(mutex->handle));
814 
815  (mutex->count)++;
816 
817  ut_a(mutex->count == 1);
818 }
819 
820 /**********************************************************/
822 UNIV_INTERN
823 void
825 /*==========*/
826  os_mutex_t mutex)
827 {
828  ut_a(mutex);
829 
830  ut_a(mutex->count == 1);
831 
832  (mutex->count)--;
833  os_fast_mutex_unlock(static_cast<os_fast_mutex_t *>(mutex->handle));
834 }
835 
836 /**********************************************************/
838 UNIV_INTERN
839 void
841 /*==========*/
842  os_mutex_t mutex)
843 {
844  ut_a(mutex);
845 
846  if (UNIV_LIKELY(!os_sync_free_called)) {
847  os_event_free_internal(mutex->event);
848  }
849 
850  if (UNIV_LIKELY(os_sync_mutex_inited)) {
851  os_mutex_enter(os_sync_mutex);
852  }
853 
854  UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
855 
856  os_mutex_count--;
857 
858  if (UNIV_LIKELY(os_sync_mutex_inited)) {
859  os_mutex_exit(os_sync_mutex);
860  }
861 
862  os_fast_mutex_free(static_cast<os_fast_mutex_t *>(mutex->handle));
863  ut_free(mutex->handle);
864  ut_free(mutex);
865 }
866 
867 /*********************************************************/
869 UNIV_INTERN
870 void
872 /*===============*/
873  os_fast_mutex_t* fast_mutex)
874 {
875 #ifdef __WIN__
876  ut_a(fast_mutex);
877 
878  InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
879 #else
880  ut_a(0 == pthread_mutex_init(fast_mutex, NULL));
881 #endif
882  if (UNIV_LIKELY(os_sync_mutex_inited)) {
883  /* When creating os_sync_mutex itself (in Unix) we cannot
884  reserve it */
885 
886  os_mutex_enter(os_sync_mutex);
887  }
888 
889  os_fast_mutex_count++;
890 
891  if (UNIV_LIKELY(os_sync_mutex_inited)) {
892  os_mutex_exit(os_sync_mutex);
893  }
894 }
895 
896 /**********************************************************/
898 UNIV_INTERN
899 void
901 /*===============*/
902  os_fast_mutex_t* fast_mutex)
903 {
904 #ifdef __WIN__
905  EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex);
906 #else
907  pthread_mutex_lock(fast_mutex);
908 #endif
909 }
910 
911 /**********************************************************/
913 UNIV_INTERN
914 void
916 /*=================*/
917  os_fast_mutex_t* fast_mutex)
918 {
919 #ifdef __WIN__
920  LeaveCriticalSection(fast_mutex);
921 #else
922  pthread_mutex_unlock(fast_mutex);
923 #endif
924 }
925 
926 /**********************************************************/
928 UNIV_INTERN
929 void
931 /*===============*/
932  os_fast_mutex_t* fast_mutex)
933 {
934 #ifdef __WIN__
935  ut_a(fast_mutex);
936 
937  DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
938 #else
939  int ret;
940 
941  ret = pthread_mutex_destroy(fast_mutex);
942 
943  if (UNIV_UNLIKELY(ret != 0)) {
944  ut_print_timestamp(stderr);
945  fprintf(stderr,
946  " InnoDB: error: return value %lu when calling\n"
947  "InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
948  fprintf(stderr,
949  "InnoDB: Byte contents of the pthread mutex at %p:\n",
950  (void*) fast_mutex);
951  ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
952  putc('\n', stderr);
953  }
954 #endif
955  if (UNIV_LIKELY(os_sync_mutex_inited)) {
956  /* When freeing the last mutexes, we have
957  already freed os_sync_mutex */
958 
959  os_mutex_enter(os_sync_mutex);
960  }
961 
962  ut_ad(os_fast_mutex_count > 0);
963  os_fast_mutex_count--;
964 
965  if (UNIV_LIKELY(os_sync_mutex_inited)) {
966  os_mutex_exit(os_sync_mutex);
967  }
968 }