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