Drizzled Public API Documentation

thr_lock.cc
00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /*
00017 Read and write locks for Posix threads. All tread must acquire
00018 all locks it needs through thr_multi_lock() to avoid dead-locks.
00019 A lock consists of a master lock (THR_LOCK), and lock instances
00020 (THR_LOCK_DATA).
00021 Any thread can have any number of lock instances (read and write:s) on
00022 any lock. All lock instances must be freed.
00023 Locks are prioritized according to:
00024 
00025 The current lock types are:
00026 
00027 TL_READ     # Low priority read
00028 TL_READ_WITH_SHARED_LOCKS
00029 TL_READ_NO_INSERT # Read without concurrent inserts
00030 TL_WRITE_ALLOW_WRITE  # Write lock that allows other writers
00031 TL_WRITE_ALLOW_READ # Write lock, but allow reading
00032 TL_WRITE_CONCURRENT_INSERT
00033       # Insert that can be mixed when selects
00034 TL_WRITE    # High priority write
00035 TL_WRITE_ONLY   # High priority write
00036       # Abort all new lock request with an error
00037 
00038 Locks are prioritized according to:
00039 
00040 WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
00041 WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
00042 
00043 Locks in the same privilege level are scheduled in first-in-first-out order.
00044 
00045 To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
00046 should put a pointer to the following functions in the lock structure:
00047 (If the pointer is zero (default), the function is not called)
00048 
00049 
00050 The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
00051 TL_WRITE_CONCURRENT_INSERT lock at the same time as multiple read locks.
00052 
00053 */
00054 
00055 #include <config.h>
00056 #include <drizzled/internal/my_sys.h>
00057 #include <drizzled/internal/thread_var.h>
00058 #include <drizzled/statistics_variables.h>
00059 #include <drizzled/pthread_globals.h>
00060 
00061 #include <drizzled/session.h>
00062 
00063 #include "thr_lock.h"
00064 #include <drizzled/internal/m_string.h>
00065 #include <errno.h>
00066 #include <list>
00067 
00068 #if TIME_WITH_SYS_TIME
00069 # include <sys/time.h>
00070 # include <time.h>
00071 #else
00072 # if HAVE_SYS_TIME_H
00073 #  include <sys/time.h>
00074 # else
00075 #  include <time.h>
00076 # endif
00077 #endif
00078 
00079 #include <drizzled/util/test.h>
00080 
00081 #include <boost/interprocess/sync/lock_options.hpp>
00082 
00083 using namespace std;
00084 
00085 namespace drizzled {
00086 
00087 uint64_t table_lock_wait_timeout;
00088 static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
00089 
00090 
00091 uint64_t max_write_lock_count= UINT64_MAX;
00092 
00093 /*
00094 ** For the future (now the thread specific cond is alloced by my_pthread.c)
00095 */
00096 
00097 static inline bool
00098 thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
00099 {
00100   return rhs == lhs;
00101 }
00102 
00103 
00104   /* Initialize a lock */
00105 
00106 void thr_lock_init(THR_LOCK *lock)
00107 {
00108   lock->read.last= &lock->read.data;
00109   lock->read_wait.last= &lock->read_wait.data;
00110   lock->write_wait.last= &lock->write_wait.data;
00111   lock->write.last= &lock->write.data;
00112 }
00113 
00114 
00115 void THR_LOCK_INFO::init()
00116 {
00117   thread_id= internal::my_thread_var2()->id;
00118   n_cursors= 0;
00119 }
00120 
00121   /* Initialize a lock instance */
00122 
00123 void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
00124 {
00125   lock= lock_arg;
00126   type= TL_UNLOCK;
00127   owner= NULL;                               /* no owner yet */
00128   status_param= param_arg;
00129   cond= NULL;
00130 }
00131 
00132 
00133 static inline bool
00134 have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
00135 {
00136   for ( ; data ; data=data->next)
00137   {
00138     if (thr_lock_owner_equal(data->owner, owner))
00139       return true;          /* Already locked by thread */
00140   }
00141   return false;
00142 }
00143 
00144 static void wake_up_waiters(THR_LOCK *lock);
00145 
00146 
00147 static enum enum_thr_lock_result wait_for_lock(Session &session, struct st_lock_list *wait, THR_LOCK_DATA *data)
00148 {
00149   boost::condition_variable_any *cond= &session.getThreadVar()->suspend;
00150   enum enum_thr_lock_result result= THR_LOCK_ABORTED;
00151   bool can_deadlock= test(data->owner->info->n_cursors);
00152 
00153   {
00154     (*wait->last)=data;       /* Wait for lock */
00155     data->prev= wait->last;
00156     wait->last= &data->next;
00157   }
00158 
00159   current_global_counters.locks_waited++;
00160 
00161   /* Set up control struct to allow others to abort locks */
00162   session.getThreadVar()->current_mutex= data->lock->native_handle();
00163   session.getThreadVar()->current_cond=  &session.getThreadVar()->suspend;
00164   data->cond= &session.getThreadVar()->suspend;;
00165 
00166   while (not session.getThreadVar()->abort)
00167   {
00168     boost::mutex::scoped_lock scoped(*data->lock->native_handle(), boost::adopt_lock_t());
00169 
00170     if (can_deadlock)
00171     {
00172       boost::xtime xt; 
00173       xtime_get(&xt, boost::TIME_UTC); 
00174       xt.sec += table_lock_wait_timeout; 
00175       if (not cond->timed_wait(scoped, xt))
00176       {
00177         result= THR_LOCK_WAIT_TIMEOUT;
00178         scoped.release();
00179         break;
00180       }
00181     }
00182     else
00183     {
00184       cond->wait(scoped);
00185     }
00186     /*
00187       We must break the wait if one of the following occurs:
00188       - the connection has been aborted (!session.getThreadVar()->abort), but
00189         this is not a delayed insert thread (in_wait_list). For a delayed
00190         insert thread the proper action at shutdown is, apparently, to
00191         acquire the lock and complete the insert.
00192       - the lock has been granted (data->cond is set to NULL by the granter),
00193         or the waiting has been aborted (additionally data->type is set to
00194         TL_UNLOCK).
00195       - the wait has timed out (rc == ETIMEDOUT)
00196       Order of checks below is important to not report about timeout
00197       if the predicate is true.
00198     */
00199     if (data->cond == NULL)
00200     {
00201       scoped.release();
00202       break;
00203     }
00204     scoped.release();
00205   }
00206   if (data->cond || data->type == TL_UNLOCK)
00207   {
00208     if (data->cond)                             /* aborted or timed out */
00209     {
00210       if (((*data->prev)=data->next))   /* remove from wait-list */
00211       {
00212   data->next->prev= data->prev;
00213       }
00214       else
00215       {
00216   wait->last=data->prev;
00217       }
00218       data->type= TL_UNLOCK;                    /* No lock */
00219       wake_up_waiters(data->lock);
00220     }
00221   }
00222   else
00223   {
00224     result= THR_LOCK_SUCCESS;
00225   }
00226   data->lock->unlock();
00227 
00228   /* The following must be done after unlock of lock->mutex */
00229   boost::mutex::scoped_lock scopedLock(session.getThreadVar()->mutex);
00230   session.getThreadVar()->current_mutex= NULL;
00231   session.getThreadVar()->current_cond= NULL;
00232 
00233   return(result);
00234 }
00235 
00236 
00237 static enum enum_thr_lock_result thr_lock(Session &session, THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
00238 {
00239   THR_LOCK *lock= data->lock;
00240   enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
00241   struct st_lock_list *wait_queue;
00242   THR_LOCK_DATA *lock_owner;
00243 
00244   data->next=0;
00245   data->cond=0;         /* safety */
00246   data->type=lock_type;
00247   data->owner= owner;                           /* Must be reset ! */
00248   lock->lock();
00249   if ((int) lock_type <= (int) TL_READ_NO_INSERT)
00250   {
00251     /* Request for READ lock */
00252     if (lock->write.data)
00253     {
00254       /* We can allow a read lock even if there is already a write lock
00255    on the table in one the following cases:
00256    - This thread alread have a write lock on the table
00257    - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
00258            and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
00259          - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
00260      and the read lock is not TL_READ_NO_INSERT
00261       */
00262 
00263       if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
00264     (lock->write.data->type <= TL_WRITE_CONCURRENT_INSERT &&
00265      (((int) lock_type <= (int) TL_READ_WITH_SHARED_LOCKS) ||
00266       (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
00267        lock->write.data->type != TL_WRITE_ALLOW_READ))))
00268       {           /* Already got a write lock */
00269   (*lock->read.last)=data;    /* Add to running FIFO */
00270   data->prev=lock->read.last;
00271   lock->read.last= &data->next;
00272   if (lock_type == TL_READ_NO_INSERT)
00273     lock->read_no_write_count++;
00274         current_global_counters.locks_immediate++;
00275   goto end;
00276       }
00277       if (lock->write.data->type == TL_WRITE_ONLY)
00278       {
00279   /* We are not allowed to get a READ lock in this case */
00280   data->type=TL_UNLOCK;
00281         result= THR_LOCK_ABORTED;               /* Can't wait for this one */
00282   goto end;
00283       }
00284     }
00285     else if (!lock->write_wait.data ||
00286        lock->write_wait.data->type <= TL_WRITE_DEFAULT ||
00287        have_old_read_lock(lock->read.data, data->owner))
00288     {           /* No important write-locks */
00289       (*lock->read.last)=data;      /* Add to running FIFO */
00290       data->prev=lock->read.last;
00291       lock->read.last= &data->next;
00292       if (lock_type == TL_READ_NO_INSERT)
00293   lock->read_no_write_count++;
00294       current_global_counters.locks_immediate++;
00295       goto end;
00296     }
00297     /*
00298       We're here if there is an active write lock or no write
00299       lock but a high priority write waiting in the write_wait queue.
00300       In the latter case we should yield the lock to the writer.
00301     */
00302     wait_queue= &lock->read_wait;
00303   }
00304   else            /* Request for WRITE lock */
00305   {
00306     if (lock_type == TL_WRITE_CONCURRENT_INSERT)
00307       data->type=lock_type= thr_upgraded_concurrent_insert_lock;
00308 
00309     if (lock->write.data)     /* If there is a write lock */
00310     {
00311       if (lock->write.data->type == TL_WRITE_ONLY)
00312       {
00313         /* Allow lock owner to bypass TL_WRITE_ONLY. */
00314         if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
00315         {
00316           /* We are not allowed to get a lock in this case */
00317           data->type=TL_UNLOCK;
00318           result= THR_LOCK_ABORTED;               /* Can't wait for this one */
00319           goto end;
00320         }
00321       }
00322 
00323       /*
00324   The following test will not work if the old lock was a
00325   TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
00326   the same thread, but this will never happen within MySQL.
00327       */
00328       if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
00329     (lock_type == TL_WRITE_ALLOW_WRITE &&
00330      !lock->write_wait.data &&
00331      lock->write.data->type == TL_WRITE_ALLOW_WRITE))
00332       {
00333   /*
00334           We have already got a write lock or all locks are
00335           TL_WRITE_ALLOW_WRITE
00336         */
00337 
00338   (*lock->write.last)=data; /* Add to running fifo */
00339   data->prev=lock->write.last;
00340   lock->write.last= &data->next;
00341         current_global_counters.locks_immediate++;
00342   goto end;
00343       }
00344     }
00345     else
00346     {
00347       if (!lock->write_wait.data)
00348       {           /* no scheduled write locks */
00349   if (!lock->read.data ||
00350       (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
00351        ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
00352          lock_type != TL_WRITE_ALLOW_WRITE) ||
00353         !lock->read_no_write_count)))
00354   {
00355     (*lock->write.last)=data;   /* Add as current write lock */
00356     data->prev=lock->write.last;
00357     lock->write.last= &data->next;
00358           current_global_counters.locks_immediate++;
00359     goto end;
00360   }
00361       }
00362     }
00363     wait_queue= &lock->write_wait;
00364   }
00365   /*
00366     Try to detect a trivial deadlock when using cursors: attempt to
00367     lock a table that is already locked by an open cursor within the
00368     same connection. lock_owner can be zero if we succumbed to a high
00369     priority writer in the write_wait queue.
00370   */
00371   lock_owner= lock->read.data ? lock->read.data : lock->write.data;
00372   if (lock_owner && lock_owner->owner->info == owner->info)
00373   {
00374     result= THR_LOCK_DEADLOCK;
00375     goto end;
00376   }
00377 
00378   /* Can't get lock yet;  Wait for it */
00379   return(wait_for_lock(session, wait_queue, data));
00380 
00381 end:
00382   lock->unlock();
00383 
00384   return(result);
00385 }
00386 
00387 
00388 static void free_all_read_locks(THR_LOCK *lock, bool using_concurrent_insert)
00389 {
00390   THR_LOCK_DATA *data= lock->read_wait.data;
00391 
00392   /* move all locks from read_wait list to read list */
00393   (*lock->read.last)=data;
00394   data->prev=lock->read.last;
00395   lock->read.last=lock->read_wait.last;
00396 
00397   /* Clear read_wait list */
00398   lock->read_wait.last= &lock->read_wait.data;
00399 
00400   do
00401   {
00402     boost::condition_variable_any *cond= data->cond;
00403     if ((int) data->type == (int) TL_READ_NO_INSERT)
00404     {
00405       if (using_concurrent_insert)
00406       {
00407   /*
00408     We can't free this lock;
00409     Link lock away from read chain back into read_wait chain
00410   */
00411   if (((*data->prev)=data->next))
00412     data->next->prev=data->prev;
00413   else
00414     lock->read.last=data->prev;
00415   *lock->read_wait.last= data;
00416   data->prev= lock->read_wait.last;
00417   lock->read_wait.last= &data->next;
00418   continue;
00419       }
00420       lock->read_no_write_count++;
00421     }
00422     data->cond= NULL;       /* Mark thread free */
00423     cond->notify_one();
00424   } while ((data=data->next));
00425   *lock->read_wait.last=0;
00426   if (!lock->read_wait.data)
00427     lock->write_lock_count=0;
00428 }
00429 
00430 /* Unlock lock and free next thread on same lock */
00431 
00432 static void thr_unlock(THR_LOCK_DATA *data)
00433 {
00434   THR_LOCK *lock=data->lock;
00435   enum thr_lock_type lock_type=data->type;
00436   lock->lock();
00437 
00438   if (((*data->prev)=data->next))   /* remove from lock-list */
00439     data->next->prev= data->prev;
00440   else if (lock_type <= TL_READ_NO_INSERT)
00441     lock->read.last=data->prev;
00442   else
00443     lock->write.last=data->prev;
00444   if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
00445   { }
00446   else
00447   { }
00448   if (lock_type == TL_READ_NO_INSERT)
00449     lock->read_no_write_count--;
00450   data->type=TL_UNLOCK;       /* Mark unlocked */
00451   wake_up_waiters(lock);
00452   lock->unlock();
00453 }
00454 
00455 
00464 static void wake_up_waiters(THR_LOCK *lock)
00465 {
00466   THR_LOCK_DATA *data;
00467   enum thr_lock_type lock_type;
00468 
00469   if (!lock->write.data)      /* If no active write locks */
00470   {
00471     data=lock->write_wait.data;
00472     if (!lock->read.data)     /* If no more locks in use */
00473     {
00474       /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
00475       if (data &&
00476     (!lock->read_wait.data || lock->read_wait.data->type <= TL_READ_WITH_SHARED_LOCKS))
00477       {
00478   if (lock->write_lock_count++ > max_write_lock_count)
00479   {
00480     /* Too many write locks in a row;  Release all waiting read locks */
00481     lock->write_lock_count=0;
00482     if (lock->read_wait.data)
00483     {
00484       free_all_read_locks(lock,0);
00485       goto end;
00486     }
00487   }
00488   for (;;)
00489   {
00490     if (((*data->prev)=data->next)) /* remove from wait-list */
00491       data->next->prev= data->prev;
00492     else
00493       lock->write_wait.last=data->prev;
00494     (*lock->write.last)=data;   /* Put in execute list */
00495     data->prev=lock->write.last;
00496     data->next=0;
00497     lock->write.last= &data->next;
00498 
00499     {
00500             boost::condition_variable_any *cond= data->cond;
00501       data->cond= NULL;       /* Mark thread free */
00502             cond->notify_one(); /* Start waiting thred */
00503     }
00504     if (data->type != TL_WRITE_ALLOW_WRITE ||
00505         !lock->write_wait.data ||
00506         lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
00507       break;
00508     data=lock->write_wait.data;   /* Free this too */
00509   }
00510   if (data->type >= TL_WRITE)
00511           goto end;
00512   /* Release possible read locks together with the write lock */
00513       }
00514       if (lock->read_wait.data)
00515   free_all_read_locks(lock,
00516           data &&
00517           (data->type == TL_WRITE_CONCURRENT_INSERT ||
00518            data->type == TL_WRITE_ALLOW_WRITE));
00519     }
00520     else if (data &&
00521        (lock_type=data->type) <= TL_WRITE_CONCURRENT_INSERT &&
00522        ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
00523          lock_type != TL_WRITE_ALLOW_WRITE) ||
00524         !lock->read_no_write_count))
00525     {
00526       do {
00527         boost::condition_variable_any *cond= data->cond;
00528   if (((*data->prev)=data->next))   /* remove from wait-list */
00529     data->next->prev= data->prev;
00530   else
00531     lock->write_wait.last=data->prev;
00532   (*lock->write.last)=data;   /* Put in execute list */
00533   data->prev=lock->write.last;
00534   lock->write.last= &data->next;
00535   data->next=0;       /* Only one write lock */
00536   data->cond= NULL;       /* Mark thread free */
00537         cond->notify_one(); /* Start waiting thread */
00538       } while (lock_type == TL_WRITE_ALLOW_WRITE &&
00539          (data=lock->write_wait.data) &&
00540          data->type == TL_WRITE_ALLOW_WRITE);
00541       if (lock->read_wait.data)
00542   free_all_read_locks(lock,
00543           (lock_type == TL_WRITE_CONCURRENT_INSERT ||
00544            lock_type == TL_WRITE_ALLOW_WRITE));
00545     }
00546     else if (!data && lock->read_wait.data)
00547     {
00548       free_all_read_locks(lock,0);
00549     }
00550   }
00551 end:
00552   return;
00553 }
00554 
00555 
00556 /*
00557 ** Get all locks in a specific order to avoid dead-locks
00558 ** Sort acording to lock position and put write_locks before read_locks if
00559 ** lock on same lock.
00560 */
00561 
00562 
00563 #define LOCK_CMP(A,B) ((unsigned char*) (A->lock) - (uint32_t) ((A)->type) < (unsigned char*) (B->lock)- (uint32_t) ((B)->type))
00564 
00565 static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
00566 {
00567   THR_LOCK_DATA **pos,**end,**prev,*tmp;
00568 
00569   /* Sort locks with insertion sort (fast because almost always few locks) */
00570 
00571   for (pos=data+1,end=data+count; pos < end ; pos++)
00572   {
00573     tmp= *pos;
00574     if (LOCK_CMP(tmp,pos[-1]))
00575     {
00576       prev=pos;
00577       do {
00578   prev[0]=prev[-1];
00579       } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
00580       prev[0]=tmp;
00581     }
00582   }
00583 }
00584 
00585 
00586 enum enum_thr_lock_result
00587 thr_multi_lock(Session &session, THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
00588 {
00589   THR_LOCK_DATA **pos,**end;
00590   if (count > 1)
00591     sort_locks(data,count);
00592   /* lock everything */
00593   for (pos=data,end=data+count; pos < end ; pos++)
00594   {
00595     enum enum_thr_lock_result result= thr_lock(session, *pos, owner, (*pos)->type);
00596     if (result != THR_LOCK_SUCCESS)
00597     {           /* Aborted */
00598       thr_multi_unlock(data,(uint32_t) (pos-data));
00599       return(result);
00600     }
00601   }
00602   return(THR_LOCK_SUCCESS);
00603 }
00604 
00605   /* free all locks */
00606 
00607 void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
00608 {
00609   THR_LOCK_DATA **pos,**end;
00610 
00611   for (pos=data,end=data+count; pos < end ; pos++)
00612   {
00613     if ((*pos)->type != TL_UNLOCK)
00614       thr_unlock(*pos);
00615   }
00616 }
00617 
00618 void DrizzleLock::unlock(uint32_t count)
00619 {
00620   THR_LOCK_DATA **pos,**end;
00621 
00622   for (pos= getLocks(),end= getLocks()+count; pos < end ; pos++)
00623   {
00624     if ((*pos)->type != TL_UNLOCK)
00625       thr_unlock(*pos);
00626   }
00627 }
00628 
00629 /*
00630   Abort all threads waiting for a lock. The lock will be upgraded to
00631   TL_WRITE_ONLY to abort any new accesses to the lock
00632 */
00633 
00634 void THR_LOCK::abort_locks()
00635 {
00636   boost::mutex::scoped_lock scopedLock(mutex);
00637 
00638   for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
00639   {
00640     local_data->type= TL_UNLOCK;      /* Mark killed */
00641     /* It's safe to signal the cond first: we're still holding the mutex. */
00642     local_data->cond->notify_one();
00643     local_data->cond= NULL;       /* Removed from list */
00644   }
00645   for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
00646   {
00647     local_data->type= TL_UNLOCK;
00648     local_data->cond->notify_one();
00649     local_data->cond= NULL;
00650   }
00651   read_wait.last= &read_wait.data;
00652   write_wait.last= &write_wait.data;
00653   read_wait.data= write_wait.data=0;
00654   if (write.data)
00655     write.data->type=TL_WRITE_ONLY;
00656 }
00657 
00658 
00659 /*
00660   Abort all locks for specific table/thread combination
00661 
00662   This is used to abort all locks for a specific thread
00663 */
00664 
00665 bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
00666 {
00667   bool found= false;
00668 
00669   boost::mutex::scoped_lock scopedLock(mutex);
00670   for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
00671   {
00672     if (local_data->owner->info->thread_id == thread_id_arg)
00673     {
00674       local_data->type= TL_UNLOCK;      /* Mark killed */
00675       /* It's safe to signal the cond first: we're still holding the mutex. */
00676       found= true;
00677       local_data->cond->notify_one();
00678       local_data->cond= 0;        /* Removed from list */
00679 
00680       if (((*local_data->prev)= local_data->next))
00681   local_data->next->prev= local_data->prev;
00682       else
00683   read_wait.last= local_data->prev;
00684     }
00685   }
00686   for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
00687   {
00688     if (local_data->owner->info->thread_id == thread_id_arg)
00689     {
00690       local_data->type= TL_UNLOCK;
00691       found= true;
00692       local_data->cond->notify_one();
00693       local_data->cond= NULL;
00694 
00695       if (((*local_data->prev)= local_data->next))
00696   local_data->next->prev= local_data->prev;
00697       else
00698   write_wait.last= local_data->prev;
00699     }
00700   }
00701   wake_up_waiters(this);
00702 
00703   return found;
00704 }
00705 
00706 } /* namespace drizzled */