Drizzled Public API Documentation

sync0arr.cc

00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
00004 Copyright (C) 2008, Google Inc.
00005 
00006 Portions of this file contain modifications contributed and copyrighted by
00007 Google, Inc. Those modifications are gratefully acknowledged and are described
00008 briefly in the InnoDB documentation. The contributions by Google are
00009 incorporated with their permission, and subject to the conditions contained in
00010 the file COPYING.Google.
00011 
00012 This program is free software; you can redistribute it and/or modify it under
00013 the terms of the GNU General Public License as published by the Free Software
00014 Foundation; version 2 of the License.
00015 
00016 This program is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License along with
00021 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00022 St, Fifth Floor, Boston, MA 02110-1301 USA
00023 
00024 *****************************************************************************/
00025 
00026 /**************************************************/
00033 #include "sync0arr.h"
00034 #ifdef UNIV_NONINL
00035 #include "sync0arr.ic"
00036 #endif
00037 
00038 #include "sync0sync.h"
00039 #include "sync0rw.h"
00040 #include "os0sync.h"
00041 #include "os0file.h"
00042 #include "srv0srv.h"
00043 
00044 /*
00045       WAIT ARRAY
00046       ==========
00047 
00048 The wait array consists of cells each of which has an
00049 an operating system event object created for it. The threads
00050 waiting for a mutex, for example, can reserve a cell
00051 in the array and suspend themselves to wait for the event
00052 to become signaled. When using the wait array, remember to make
00053 sure that some thread holding the synchronization object
00054 will eventually know that there is a waiter in the array and
00055 signal the object, to prevent infinite wait.
00056 Why we chose to implement a wait array? First, to make
00057 mutexes fast, we had to code our own implementation of them,
00058 which only in usually uncommon cases resorts to using
00059 slow operating system primitives. Then we had the choice of
00060 assigning a unique OS event for each mutex, which would
00061 be simpler, or using a global wait array. In some operating systems,
00062 the global wait array solution is more efficient and flexible,
00063 because we can do with a very small number of OS events,
00064 say 200. In NT 3.51, allocating events seems to be a quadratic
00065 algorithm, because 10 000 events are created fast, but
00066 100 000 events takes a couple of minutes to create.
00067 
00068 As of 5.0.30 the above mentioned design is changed. Since now
00069 OS can handle millions of wait events efficiently, we no longer
00070 have this concept of each cell of wait array having one event.
00071 Instead, now the event that a thread wants to wait on is embedded
00072 in the wait object (mutex or rw_lock). We still keep the global
00073 wait array for the sake of diagnostics and also to avoid infinite
00074 wait The error_monitor thread scans the global wait array to signal
00075 any waiting threads who have missed the signal. */
00076 
00080 struct sync_cell_struct {
00081   void*   wait_object;  
00084   mutex_t*  old_wait_mutex; 
00085   rw_lock_t*  old_wait_rw_lock;
00088   ulint   request_type; 
00090   const char* file;   
00092   ulint   line;   
00094   os_thread_id_t  thread;   
00096   ibool   waiting;  
00099   ib_int64_t  signal_count; 
00107   time_t    reservation_time;
00109 };
00110 
00111 /* NOTE: It is allowed for a thread to wait
00112 for an event allocated for the array without owning the
00113 protecting mutex (depending on the case: OS or database mutex), but
00114 all changes (set or reset) to the state of the event must be made
00115 while owning the mutex. */
00116 
00118 struct sync_array_struct {
00119   ulint   n_reserved; 
00121   ulint   n_cells;  
00123   sync_cell_t*  array;    
00124   ulint   protection; 
00126   mutex_t   mutex;    
00128   os_mutex_t  os_mutex; 
00135   ulint   sg_count; 
00137   ulint   res_count;  
00139 };
00140 
00141 #ifdef UNIV_PFS_MUTEX
00142 /* Key to register the mutex with performance schema */
00143 UNIV_INTERN mysql_pfs_key_t syn_arr_mutex_key;
00144 #endif
00145 
00146 #ifdef UNIV_SYNC_DEBUG
00147 /******************************************************************/
00151 static
00152 ibool
00153 sync_array_detect_deadlock(
00154 /*=======================*/
00155   sync_array_t* arr,  
00157   sync_cell_t*  start,  
00158   sync_cell_t*  cell, 
00159   ulint   depth); 
00160 #endif /* UNIV_SYNC_DEBUG */
00161 
00162 /*****************************************************************/
00165 static
00166 sync_cell_t*
00167 sync_array_get_nth_cell(
00168 /*====================*/
00169   sync_array_t* arr,  
00170   ulint   n)  
00171 {
00172   ut_a(arr);
00173   ut_a(n < arr->n_cells);
00174 
00175   return(arr->array + n);
00176 }
00177 
00178 /******************************************************************/
00180 static
00181 void
00182 sync_array_enter(
00183 /*=============*/
00184   sync_array_t* arr)  
00185 {
00186   ulint protection;
00187 
00188   protection = arr->protection;
00189 
00190   if (protection == SYNC_ARRAY_OS_MUTEX) {
00191     os_mutex_enter(arr->os_mutex);
00192   } else if (protection == SYNC_ARRAY_MUTEX) {
00193     mutex_enter(&(arr->mutex));
00194   } else {
00195     ut_error;
00196   }
00197 }
00198 
00199 /******************************************************************/
00201 static
00202 void
00203 sync_array_exit(
00204 /*============*/
00205   sync_array_t* arr)  
00206 {
00207   ulint protection;
00208 
00209   protection = arr->protection;
00210 
00211   if (protection == SYNC_ARRAY_OS_MUTEX) {
00212     os_mutex_exit(arr->os_mutex);
00213   } else if (protection == SYNC_ARRAY_MUTEX) {
00214     mutex_exit(&(arr->mutex));
00215   } else {
00216     ut_error;
00217   }
00218 }
00219 
00220 /*******************************************************************/
00225 UNIV_INTERN
00226 sync_array_t*
00227 sync_array_create(
00228 /*==============*/
00229   ulint n_cells,  
00231   ulint protection) 
00234 {
00235   ulint   sz;
00236   sync_array_t* arr;
00237 
00238   ut_a(n_cells > 0);
00239 
00240   /* Allocate memory for the data structures */
00241   arr = static_cast<sync_array_t *>(ut_malloc(sizeof(sync_array_t)));
00242   memset(arr, 0x0, sizeof(*arr));
00243 
00244   sz = sizeof(sync_cell_t) * n_cells;
00245   arr->array = static_cast<sync_cell_t *>(ut_malloc(sz));
00246   memset(arr->array, 0x0, sz);
00247 
00248   arr->n_cells = n_cells;
00249   arr->protection = protection;
00250 
00251   /* Then create the mutex to protect the wait array complex */
00252   if (protection == SYNC_ARRAY_OS_MUTEX) {
00253     arr->os_mutex = os_mutex_create();
00254   } else if (protection == SYNC_ARRAY_MUTEX) {
00255     mutex_create(syn_arr_mutex_key,
00256            &arr->mutex, SYNC_NO_ORDER_CHECK);
00257   } else {
00258     ut_error;
00259   }
00260 
00261   return(arr);
00262 }
00263 
00264 /******************************************************************/
00266 UNIV_INTERN
00267 void
00268 sync_array_free(
00269 /*============*/
00270   sync_array_t* arr)  
00271 {
00272   ulint   protection;
00273 
00274   ut_a(arr->n_reserved == 0);
00275 
00276   sync_array_validate(arr);
00277 
00278   protection = arr->protection;
00279 
00280   /* Release the mutex protecting the wait array complex */
00281 
00282   if (protection == SYNC_ARRAY_OS_MUTEX) {
00283     os_mutex_free(arr->os_mutex);
00284   } else if (protection == SYNC_ARRAY_MUTEX) {
00285     mutex_free(&(arr->mutex));
00286   } else {
00287     ut_error;
00288   }
00289 
00290   ut_free(arr->array);
00291   ut_free(arr);
00292 }
00293 
00294 /********************************************************************/
00297 UNIV_INTERN
00298 void
00299 sync_array_validate(
00300 /*================*/
00301   sync_array_t* arr)  
00302 {
00303   ulint   i;
00304   sync_cell_t*  cell;
00305   ulint   count   = 0;
00306 
00307   sync_array_enter(arr);
00308 
00309   for (i = 0; i < arr->n_cells; i++) {
00310     cell = sync_array_get_nth_cell(arr, i);
00311     if (cell->wait_object != NULL) {
00312       count++;
00313     }
00314   }
00315 
00316   ut_a(count == arr->n_reserved);
00317 
00318   sync_array_exit(arr);
00319 }
00320 
00321 /*******************************************************************/
00323 static
00324 os_event_t
00325 sync_cell_get_event(
00326 /*================*/
00327   sync_cell_t*  cell) 
00328 {
00329   ulint type = cell->request_type;
00330 
00331   if (type == SYNC_MUTEX) {
00332     return(((mutex_t *) cell->wait_object)->event);
00333   } else if (type == RW_LOCK_WAIT_EX) {
00334     return(((rw_lock_t *) cell->wait_object)->wait_ex_event);
00335   } else { /* RW_LOCK_SHARED and RW_LOCK_EX wait on the same event */
00336     return(((rw_lock_t *) cell->wait_object)->event);
00337   }
00338 }
00339 
00340 /******************************************************************/
00343 UNIV_INTERN
00344 void
00345 sync_array_reserve_cell(
00346 /*====================*/
00347   sync_array_t* arr,  
00348   void*   object, 
00349   ulint   type, 
00350   const char* file, 
00351   ulint   line, 
00352   ulint*    index)  
00353 {
00354   sync_cell_t*  cell;
00355   os_event_t      event;
00356   ulint   i;
00357 
00358   ut_a(object);
00359   ut_a(index);
00360 
00361   sync_array_enter(arr);
00362 
00363   arr->res_count++;
00364 
00365   /* Reserve a new cell. */
00366   for (i = 0; i < arr->n_cells; i++) {
00367     cell = sync_array_get_nth_cell(arr, i);
00368 
00369     if (cell->wait_object == NULL) {
00370 
00371       cell->waiting = FALSE;
00372       cell->wait_object = object;
00373 
00374       if (type == SYNC_MUTEX) {
00375         cell->old_wait_mutex = static_cast<mutex_struct *>(object);
00376       } else {
00377         cell->old_wait_rw_lock = static_cast<rw_lock_struct *>(object);
00378       }
00379 
00380       cell->request_type = type;
00381 
00382       cell->file = file;
00383       cell->line = line;
00384 
00385       arr->n_reserved++;
00386 
00387       *index = i;
00388 
00389       sync_array_exit(arr);
00390 
00391       /* Make sure the event is reset and also store
00392       the value of signal_count at which the event
00393       was reset. */
00394                         event = sync_cell_get_event(cell);
00395       cell->signal_count = os_event_reset(event);
00396 
00397       cell->reservation_time = time(NULL);
00398 
00399       cell->thread = os_thread_get_curr_id();
00400 
00401       return;
00402     }
00403   }
00404 
00405   ut_error; /* No free cell found */
00406 
00407   return;
00408 }
00409 
00410 /******************************************************************/
00415 UNIV_INTERN
00416 void
00417 sync_array_wait_event(
00418 /*==================*/
00419   sync_array_t* arr,  
00420   ulint   index)  
00421 {
00422   sync_cell_t*  cell;
00423   os_event_t  event;
00424 
00425   ut_a(arr);
00426 
00427   sync_array_enter(arr);
00428 
00429   cell = sync_array_get_nth_cell(arr, index);
00430 
00431   ut_a(cell->wait_object);
00432   ut_a(!cell->waiting);
00433   ut_ad(os_thread_get_curr_id() == cell->thread);
00434 
00435   event = sync_cell_get_event(cell);
00436     cell->waiting = TRUE;
00437 
00438 #ifdef UNIV_SYNC_DEBUG
00439 
00440   /* We use simple enter to the mutex below, because if
00441   we cannot acquire it at once, mutex_enter would call
00442   recursively sync_array routines, leading to trouble.
00443   rw_lock_debug_mutex freezes the debug lists. */
00444 
00445   rw_lock_debug_mutex_enter();
00446 
00447   if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) {
00448 
00449     fputs("########################################\n", stderr);
00450     ut_error;
00451   }
00452 
00453   rw_lock_debug_mutex_exit();
00454 #endif
00455   sync_array_exit(arr);
00456 
00457   os_event_wait_low(event, cell->signal_count);
00458 
00459   sync_array_free_cell(arr, index);
00460 }
00461 
00462 /******************************************************************/
00464 static
00465 void
00466 sync_array_cell_print(
00467 /*==================*/
00468   FILE*   file, 
00469   sync_cell_t*  cell) 
00470 {
00471   mutex_t*  mutex;
00472   rw_lock_t*  rwlock;
00473   ulint   type;
00474   ulint   writer;
00475 
00476   type = cell->request_type;
00477 
00478   fprintf(file,
00479     "--Thread %lu has waited at %s line %lu"
00480     " for %.2f seconds the semaphore:\n",
00481     (ulong) os_thread_pf(cell->thread), cell->file,
00482     (ulong) cell->line,
00483     difftime(time(NULL), cell->reservation_time));
00484 
00485   if (type == SYNC_MUTEX) {
00486     /* We use old_wait_mutex in case the cell has already
00487     been freed meanwhile */
00488     mutex = cell->old_wait_mutex;
00489 
00490     fprintf(file,
00491       "Mutex at %p created file %s line %lu, lock var %lu\n"
00492 #ifdef UNIV_SYNC_DEBUG
00493       "Last time reserved in file %s line %lu, "
00494 #endif /* UNIV_SYNC_DEBUG */
00495       "waiters flag %lu\n",
00496       (void*) mutex, mutex->cfile_name, (ulong) mutex->cline,
00497       (ulong) mutex->lock_word,
00498 #ifdef UNIV_SYNC_DEBUG
00499       mutex->file_name, (ulong) mutex->line,
00500 #endif /* UNIV_SYNC_DEBUG */
00501       (ulong) mutex->waiters);
00502 
00503   } else if (type == RW_LOCK_EX
00504        || type == RW_LOCK_WAIT_EX
00505        || type == RW_LOCK_SHARED) {
00506 
00507     fputs(type == RW_LOCK_EX ? "X-lock on"
00508           : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on"
00509           : "S-lock on", file);
00510 
00511     rwlock = cell->old_wait_rw_lock;
00512 
00513     fprintf(file,
00514       " RW-latch at %p created in file %s line %lu\n",
00515       (void*) rwlock, rwlock->cfile_name,
00516       (ulong) rwlock->cline);
00517     writer = rw_lock_get_writer(rwlock);
00518     if (writer != RW_LOCK_NOT_LOCKED) {
00519       fprintf(file,
00520         "a writer (thread id %lu) has"
00521         " reserved it in mode %s",
00522         (ulong) os_thread_pf(rwlock->writer_thread),
00523         writer == RW_LOCK_EX
00524         ? " exclusive\n"
00525         : " wait exclusive\n");
00526     }
00527 
00528     fprintf(file,
00529       "number of readers %lu, waiters flag %lu, "
00530                         "lock_word: %lx\n"
00531       "Last time read locked in file %s line %lu\n"
00532       "Last time write locked in file %s line %lu\n",
00533       (ulong) rw_lock_get_reader_count(rwlock),
00534       (ulong) rwlock->waiters,
00535       rwlock->lock_word,
00536       rwlock->last_s_file_name,
00537       (ulong) rwlock->last_s_line,
00538       rwlock->last_x_file_name,
00539       (ulong) rwlock->last_x_line);
00540   } else {
00541     ut_error;
00542   }
00543 
00544   if (!cell->waiting) {
00545     fputs("wait has ended\n", file);
00546   }
00547 }
00548 
00549 #ifdef UNIV_SYNC_DEBUG
00550 /******************************************************************/
00553 static
00554 sync_cell_t*
00555 sync_array_find_thread(
00556 /*===================*/
00557   sync_array_t* arr,  
00558   os_thread_id_t  thread) 
00559 {
00560   ulint   i;
00561   sync_cell_t*  cell;
00562 
00563   for (i = 0; i < arr->n_cells; i++) {
00564 
00565     cell = sync_array_get_nth_cell(arr, i);
00566 
00567     if (cell->wait_object != NULL
00568         && os_thread_eq(cell->thread, thread)) {
00569 
00570       return(cell); /* Found */
00571     }
00572   }
00573 
00574   return(NULL); /* Not found */
00575 }
00576 
00577 /******************************************************************/
00580 static
00581 ibool
00582 sync_array_deadlock_step(
00583 /*=====================*/
00584   sync_array_t* arr,  
00586   sync_cell_t*  start,  
00588   os_thread_id_t  thread, 
00589   ulint   pass, 
00590   ulint   depth)  
00591 {
00592   sync_cell_t*  new;
00593   ibool   ret;
00594 
00595   depth++;
00596 
00597   if (pass != 0) {
00598     /* If pass != 0, then we do not know which threads are
00599     responsible of releasing the lock, and no deadlock can
00600     be detected. */
00601 
00602     return(FALSE);
00603   }
00604 
00605   new = sync_array_find_thread(arr, thread);
00606 
00607   if (new == start) {
00608     /* Stop running of other threads */
00609 
00610     ut_dbg_stop_threads = TRUE;
00611 
00612     /* Deadlock */
00613     fputs("########################################\n"
00614           "DEADLOCK of threads detected!\n", stderr);
00615 
00616     return(TRUE);
00617 
00618   } else if (new) {
00619     ret = sync_array_detect_deadlock(arr, start, new, depth);
00620 
00621     if (ret) {
00622       return(TRUE);
00623     }
00624   }
00625   return(FALSE);
00626 }
00627 
00628 /******************************************************************/
00632 static
00633 ibool
00634 sync_array_detect_deadlock(
00635 /*=======================*/
00636   sync_array_t* arr,  
00638   sync_cell_t*  start,  
00639   sync_cell_t*  cell, 
00640   ulint   depth)  
00641 {
00642   mutex_t*  mutex;
00643   rw_lock_t*  lock;
00644   os_thread_id_t  thread;
00645   ibool   ret;
00646   rw_lock_debug_t*debug;
00647 
00648   ut_a(arr);
00649   ut_a(start);
00650   ut_a(cell);
00651   ut_ad(cell->wait_object);
00652   ut_ad(os_thread_get_curr_id() == start->thread);
00653   ut_ad(depth < 100);
00654 
00655   depth++;
00656 
00657   if (!cell->waiting) {
00658 
00659     return(FALSE); /* No deadlock here */
00660   }
00661 
00662   if (cell->request_type == SYNC_MUTEX) {
00663 
00664     mutex = cell->wait_object;
00665 
00666     if (mutex_get_lock_word(mutex) != 0) {
00667 
00668       thread = mutex->thread_id;
00669 
00670       /* Note that mutex->thread_id above may be
00671       also OS_THREAD_ID_UNDEFINED, because the
00672       thread which held the mutex maybe has not
00673       yet updated the value, or it has already
00674       released the mutex: in this case no deadlock
00675       can occur, as the wait array cannot contain
00676       a thread with ID_UNDEFINED value. */
00677 
00678       ret = sync_array_deadlock_step(arr, start, thread, 0,
00679                    depth);
00680       if (ret) {
00681         fprintf(stderr,
00682       "Mutex %p owned by thread %lu file %s line %lu\n",
00683           mutex, (ulong) os_thread_pf(mutex->thread_id),
00684           mutex->file_name, (ulong) mutex->line);
00685         sync_array_cell_print(stderr, cell);
00686 
00687         return(TRUE);
00688       }
00689     }
00690 
00691     return(FALSE); /* No deadlock */
00692 
00693   } else if (cell->request_type == RW_LOCK_EX
00694        || cell->request_type == RW_LOCK_WAIT_EX) {
00695 
00696     lock = cell->wait_object;
00697 
00698     debug = UT_LIST_GET_FIRST(lock->debug_list);
00699 
00700     while (debug != NULL) {
00701 
00702       thread = debug->thread_id;
00703 
00704       if (((debug->lock_type == RW_LOCK_EX)
00705            && !os_thread_eq(thread, cell->thread))
00706           || ((debug->lock_type == RW_LOCK_WAIT_EX)
00707         && !os_thread_eq(thread, cell->thread))
00708           || (debug->lock_type == RW_LOCK_SHARED)) {
00709 
00710         /* The (wait) x-lock request can block
00711         infinitely only if someone (can be also cell
00712         thread) is holding s-lock, or someone
00713         (cannot be cell thread) (wait) x-lock, and
00714         he is blocked by start thread */
00715 
00716         ret = sync_array_deadlock_step(
00717           arr, start, thread, debug->pass,
00718           depth);
00719         if (ret) {
00720 print:
00721           fprintf(stderr, "rw-lock %p ",
00722             (void*) lock);
00723           sync_array_cell_print(stderr, cell);
00724           rw_lock_debug_print(debug);
00725           return(TRUE);
00726         }
00727       }
00728 
00729       debug = UT_LIST_GET_NEXT(list, debug);
00730     }
00731 
00732     return(FALSE);
00733 
00734   } else if (cell->request_type == RW_LOCK_SHARED) {
00735 
00736     lock = cell->wait_object;
00737     debug = UT_LIST_GET_FIRST(lock->debug_list);
00738 
00739     while (debug != NULL) {
00740 
00741       thread = debug->thread_id;
00742 
00743       if ((debug->lock_type == RW_LOCK_EX)
00744           || (debug->lock_type == RW_LOCK_WAIT_EX)) {
00745 
00746         /* The s-lock request can block infinitely
00747         only if someone (can also be cell thread) is
00748         holding (wait) x-lock, and he is blocked by
00749         start thread */
00750 
00751         ret = sync_array_deadlock_step(
00752           arr, start, thread, debug->pass,
00753           depth);
00754         if (ret) {
00755           goto print;
00756         }
00757       }
00758 
00759       debug = UT_LIST_GET_NEXT(list, debug);
00760     }
00761 
00762     return(FALSE);
00763 
00764   } else {
00765     ut_error;
00766   }
00767 
00768   return(TRUE); /* Execution never reaches this line: for compiler
00769       fooling only */
00770 }
00771 #endif /* UNIV_SYNC_DEBUG */
00772 
00773 /******************************************************************/
00775 static
00776 ibool
00777 sync_arr_cell_can_wake_up(
00778 /*======================*/
00779   sync_cell_t*  cell) 
00780 {
00781   mutex_t*  mutex;
00782   rw_lock_t*  lock;
00783 
00784   if (cell->request_type == SYNC_MUTEX) {
00785 
00786     mutex = static_cast<mutex_t *>(cell->wait_object);
00787 
00788     if (mutex_get_lock_word(mutex) == 0) {
00789 
00790       return(TRUE);
00791     }
00792 
00793   } else if (cell->request_type == RW_LOCK_EX) {
00794 
00795     lock = static_cast<rw_lock_t *>(cell->wait_object);
00796 
00797     if (lock->lock_word > 0) {
00798     /* Either unlocked or only read locked. */
00799 
00800       return(TRUE);
00801     }
00802 
00803         } else if (cell->request_type == RW_LOCK_WAIT_EX) {
00804 
00805     lock = static_cast<rw_lock_t *>(cell->wait_object);
00806 
00807                 /* lock_word == 0 means all readers have left */
00808     if (lock->lock_word == 0) {
00809 
00810       return(TRUE);
00811     }
00812   } else if (cell->request_type == RW_LOCK_SHARED) {
00813     lock = static_cast<rw_lock_t *>(cell->wait_object);
00814 
00815                 /* lock_word > 0 means no writer or reserved writer */
00816     if (lock->lock_word > 0) {
00817 
00818       return(TRUE);
00819     }
00820   }
00821 
00822   return(FALSE);
00823 }
00824 
00825 /******************************************************************/
00828 UNIV_INTERN
00829 void
00830 sync_array_free_cell(
00831 /*=================*/
00832   sync_array_t* arr,  
00833   ulint   index)  
00834 {
00835   sync_cell_t*  cell;
00836 
00837   sync_array_enter(arr);
00838 
00839   cell = sync_array_get_nth_cell(arr, index);
00840 
00841   ut_a(cell->wait_object != NULL);
00842 
00843   cell->waiting = FALSE;
00844   cell->wait_object =  NULL;
00845   cell->signal_count = 0;
00846 
00847   ut_a(arr->n_reserved > 0);
00848   arr->n_reserved--;
00849 
00850   sync_array_exit(arr);
00851 }
00852 
00853 /**********************************************************************/
00855 UNIV_INTERN
00856 void
00857 sync_array_object_signalled(
00858 /*========================*/
00859   sync_array_t* arr)  
00860 {
00861 #ifdef HAVE_ATOMIC_BUILTINS
00862   (void) os_atomic_increment_ulint(&arr->sg_count, 1);
00863 #else
00864   sync_array_enter(arr);
00865 
00866   arr->sg_count++;
00867 
00868   sync_array_exit(arr);
00869 #endif
00870 }
00871 
00872 /**********************************************************************/
00880 UNIV_INTERN
00881 void
00882 sync_arr_wake_threads_if_sema_free(void)
00883 /*====================================*/
00884 {
00885   sync_array_t* arr = sync_primary_wait_array;
00886   sync_cell_t*  cell;
00887   ulint   count;
00888   ulint   i;
00889   os_event_t      event;
00890 
00891   sync_array_enter(arr);
00892 
00893   i = 0;
00894   count = 0;
00895 
00896   while (count < arr->n_reserved) {
00897 
00898     cell = sync_array_get_nth_cell(arr, i);
00899     i++;
00900 
00901     if (cell->wait_object == NULL) {
00902       continue;
00903     }
00904       count++;
00905 
00906       if (sync_arr_cell_can_wake_up(cell)) {
00907 
00908       event = sync_cell_get_event(cell);
00909 
00910       os_event_set(event);
00911     }
00912 
00913   }
00914 
00915   sync_array_exit(arr);
00916 }
00917 
00918 /**********************************************************************/
00921 UNIV_INTERN
00922 ibool
00923 sync_array_print_long_waits(void)
00924 /*=============================*/
00925 {
00926   sync_cell_t*  cell;
00927   ibool   old_val;
00928   ibool   noticed = FALSE;
00929   ulint   i;
00930   ulint   fatal_timeout = srv_fatal_semaphore_wait_threshold;
00931   ibool   fatal = FALSE;
00932 
00933   for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
00934 
00935     cell = sync_array_get_nth_cell(sync_primary_wait_array, i);
00936 
00937     if (cell->wait_object != NULL && cell->waiting
00938         && difftime(time(NULL), cell->reservation_time) > 240) {
00939       fputs("InnoDB: Warning: a long semaphore wait:\n",
00940             stderr);
00941       sync_array_cell_print(stderr, cell);
00942       noticed = TRUE;
00943     }
00944 
00945     if (cell->wait_object != NULL && cell->waiting
00946         && difftime(time(NULL), cell->reservation_time)
00947         > fatal_timeout) {
00948       fatal = TRUE;
00949     }
00950   }
00951 
00952   if (noticed) {
00953     fprintf(stderr,
00954       "InnoDB: ###### Starts InnoDB Monitor"
00955       " for 30 secs to print diagnostic info:\n");
00956     old_val = srv_print_innodb_monitor;
00957 
00958     /* If some crucial semaphore is reserved, then also the InnoDB
00959     Monitor can hang, and we do not get diagnostics. Since in
00960     many cases an InnoDB hang is caused by a pwrite() or a pread()
00961     call hanging inside the operating system, let us print right
00962     now the values of pending calls of these. */
00963 
00964     fprintf(stderr,
00965       "InnoDB: Pending preads %lu, pwrites %lu\n",
00966       (ulong)os_file_n_pending_preads,
00967       (ulong)os_file_n_pending_pwrites);
00968 
00969     srv_print_innodb_monitor = TRUE;
00970     os_event_set(srv_lock_timeout_thread_event);
00971 
00972     os_thread_sleep(30000000);
00973 
00974     srv_print_innodb_monitor = old_val;
00975     fprintf(stderr,
00976       "InnoDB: ###### Diagnostic info printed"
00977       " to the standard error stream\n");
00978   }
00979 
00980   return(fatal);
00981 }
00982 
00983 /**********************************************************************/
00985 static
00986 void
00987 sync_array_output_info(
00988 /*===================*/
00989   FILE*   file, 
00990   sync_array_t* arr)  
00992 {
00993   sync_cell_t*  cell;
00994   ulint   count;
00995   ulint   i;
00996 
00997   fprintf(file,
00998     "OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
00999             (long) arr->res_count, (long) arr->sg_count);
01000   i = 0;
01001   count = 0;
01002 
01003   while (count < arr->n_reserved) {
01004 
01005     cell = sync_array_get_nth_cell(arr, i);
01006 
01007   if (cell->wait_object != NULL) {
01008     count++;
01009       sync_array_cell_print(file, cell);
01010     }
01011 
01012     i++;
01013   }
01014 }
01015 
01016 /**********************************************************************/
01018 UNIV_INTERN
01019 void
01020 sync_array_print_info(
01021 /*==================*/
01022   FILE*   file, 
01023   sync_array_t* arr)  
01024 {
01025   sync_array_enter(arr);
01026 
01027   sync_array_output_info(file, arr);
01028 
01029   sync_array_exit(arr);
01030 }