thr_mutex.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:10k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000-2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* This makes a wrapper for mutex handling to make it easier to debug mutex */
  14. #include <my_global.h>
  15. #if defined(TARGET_OS_LINUX) && !defined (__USE_UNIX98)
  16. #define __USE_UNIX98 /* To get rw locks under Linux */
  17. #endif
  18. #if defined(THREAD) && defined(SAFE_MUTEX)
  19. #undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
  20. #include "mysys_priv.h"
  21. #include "my_static.h"
  22. #include <m_string.h>
  23. #ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
  24. /* Remove wrappers */
  25. #undef pthread_mutex_t
  26. #undef pthread_mutex_init
  27. #undef pthread_mutex_lock
  28. #undef pthread_mutex_unlock
  29. #undef pthread_mutex_destroy
  30. #undef pthread_cond_wait
  31. #undef pthread_cond_timedwait
  32. #ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
  33. #define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
  34. #endif
  35. #endif /* DO_NOT_REMOVE_THREAD_WRAPPERS */
  36. static pthread_mutex_t THR_LOCK_mutex;
  37. static ulong safe_mutex_count= 0; /* Number of mutexes created */
  38. #ifdef SAFE_MUTEX_DETECT_DESTROY
  39. static struct st_safe_mutex_info_t *safe_mutex_root= NULL;
  40. #endif
  41. void safe_mutex_global_init(void)
  42. {
  43.   pthread_mutex_init(&THR_LOCK_mutex,MY_MUTEX_INIT_FAST);
  44. }
  45. int safe_mutex_init(safe_mutex_t *mp,
  46.     const pthread_mutexattr_t *attr __attribute__((unused)),
  47.     const char *file,
  48.     uint line)
  49. {
  50.   bzero((char*) mp,sizeof(*mp));
  51.   pthread_mutex_init(&mp->global,MY_MUTEX_INIT_ERRCHK);
  52.   pthread_mutex_init(&mp->mutex,attr);
  53.   /* Mark that mutex is initialized */
  54.   mp->file= file;
  55.   mp->line= line;
  56. #ifdef SAFE_MUTEX_DETECT_DESTROY
  57.   /*
  58.     Monitor the freeing of mutexes.  This code depends on single thread init
  59.     and destroy
  60.   */
  61.   if ((mp->info= (safe_mutex_info_t *) malloc(sizeof(safe_mutex_info_t))))
  62.   {
  63.     struct st_safe_mutex_info_t *info =mp->info;
  64.     info->init_file= file;
  65.     info->init_line= line;
  66.     info->prev= NULL;
  67.     info->next= NULL;
  68.     pthread_mutex_lock(&THR_LOCK_mutex);
  69.     if ((info->next= safe_mutex_root))
  70.       safe_mutex_root->prev= info;
  71.     safe_mutex_root= info;
  72.     safe_mutex_count++;
  73.     pthread_mutex_unlock(&THR_LOCK_mutex);
  74.   }
  75. #else
  76.   thread_safe_increment(safe_mutex_count, &THR_LOCK_mutex);
  77. #endif /* SAFE_MUTEX_DETECT_DESTROY */
  78.   return 0;
  79. }
  80. int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
  81. {
  82.   int error;
  83.   if (!mp->file)
  84.   {
  85.     fprintf(stderr,
  86.     "safe_mutex: Trying to lock unitialized mutex at %s, line %dn",
  87.     file, line);
  88.     fflush(stderr);
  89.     abort();
  90.   }
  91.     
  92.   pthread_mutex_lock(&mp->global);
  93.   if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread))
  94.   {
  95.     fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d in thread %sn",
  96.     file,line,mp->file, mp->line, my_thread_name());
  97.     fflush(stderr);
  98.     abort();
  99.   }
  100.   pthread_mutex_unlock(&mp->global);
  101.   error=pthread_mutex_lock(&mp->mutex);
  102.   if (error || (error=pthread_mutex_lock(&mp->global)))
  103.   {
  104.     fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %dn",
  105.     error, file, line);
  106.     fflush(stderr);
  107.     abort();
  108.   }
  109.   if (mp->count++)
  110.   {
  111.     fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, 
  112. line %d more than 1 timen", file,line);
  113.     fflush(stderr);
  114.     abort();
  115.   }
  116.   mp->thread=pthread_self();
  117.   mp->file= file;
  118.   mp->line=line;
  119.   pthread_mutex_unlock(&mp->global);
  120.   return error;
  121. }
  122. int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
  123. {
  124.   int error;
  125.   pthread_mutex_lock(&mp->global);
  126.   if (mp->count == 0)
  127.   {
  128.     fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %dn            Last used at %s, line: %dn",
  129.     file,line,mp->file ? mp->file : "",mp->line);
  130.     fflush(stderr);
  131.     abort();
  132.   }
  133.   if (!pthread_equal(pthread_self(),mp->thread))
  134.   {
  135.     fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d  that was locked by another thread at: %s, line: %dn",
  136.     file,line,mp->file,mp->line);
  137.     fflush(stderr);
  138.     abort();
  139.   }
  140.   mp->count--;
  141. #ifdef __WIN__
  142.   pthread_mutex_unlock(&mp->mutex);
  143.   error=0;
  144. #else
  145.   error=pthread_mutex_unlock(&mp->mutex);
  146.   if (error)
  147.   {
  148.     fprintf(stderr,"safe_mutex: Got error: %d (%d) when trying to unlock mutex at %s, line %dn", error, errno, file, line);
  149.     fflush(stderr);
  150.     abort();
  151.   }
  152. #endif /* __WIN__ */
  153.   pthread_mutex_unlock(&mp->global);
  154.   return error;
  155. }
  156. int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
  157.    uint line)
  158. {
  159.   int error;
  160.   pthread_mutex_lock(&mp->global);
  161.   if (mp->count == 0)
  162.   {
  163.     fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %dn",file,line);
  164.     fflush(stderr);
  165.     abort();
  166.   }
  167.   if (!pthread_equal(pthread_self(),mp->thread))
  168.   {
  169.     fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d  that was locked by another thread at: %s, line: %dn",
  170.     file,line,mp->file,mp->line);
  171.     fflush(stderr);
  172.     abort();
  173.   }
  174.   if (mp->count-- != 1)
  175.   {
  176.     fprintf(stderr,"safe_mutex:  Count was %d on locked mutex at %s, line %dn",
  177.     mp->count+1, file, line);
  178.     fflush(stderr);
  179.     abort();
  180.   }
  181.   pthread_mutex_unlock(&mp->global);
  182.   error=pthread_cond_wait(cond,&mp->mutex);
  183.   pthread_mutex_lock(&mp->global);
  184.   if (error)
  185.   {
  186.     fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_wait at %s, line %dn", error, errno, file, line);
  187.     fflush(stderr);
  188.     abort();
  189.   }
  190.   if (mp->count++)
  191.   {
  192.     fprintf(stderr,
  193.     "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %dn",
  194.     mp->count-1, my_thread_id(), file, line);
  195.     fflush(stderr);
  196.     abort();
  197.   }
  198.   mp->thread=pthread_self();
  199.   mp->file= file;
  200.   mp->line=line;
  201.   pthread_mutex_unlock(&mp->global);
  202.   return error;
  203. }
  204. int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
  205. struct timespec *abstime,
  206. const char *file, uint line)
  207. {
  208.   int error;
  209.   pthread_mutex_lock(&mp->global);
  210.   if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
  211.   {
  212.     fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutexn",file,line);
  213.     fflush(stderr);
  214.     abort();
  215.   }
  216.   mp->count--; /* Mutex will be released */
  217.   pthread_mutex_unlock(&mp->global);
  218.   error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
  219. #ifdef EXTRA_DEBUG
  220.   if (error && (error != EINTR && error != ETIMEDOUT))
  221.   {
  222.     fprintf(stderr,"safe_mutex: Got error: %d (%d) when doing a safe_mutex_timedwait at %s, line %dn", error, errno, file, line);
  223.   }
  224. #endif
  225.   pthread_mutex_lock(&mp->global);
  226.   if (mp->count++)
  227.   {
  228.     fprintf(stderr,
  229.     "safe_mutex:  Count was %d in thread 0x%lx when locking mutex at %s, line %d (error: %d (%d))n",
  230.     mp->count-1, my_thread_id(), file, line, error, error);
  231.     fflush(stderr);
  232.     abort();
  233.   }
  234.   mp->thread=pthread_self();
  235.   mp->file= file;
  236.   mp->line=line;
  237.   pthread_mutex_unlock(&mp->global);
  238.   return error;
  239. }
  240. int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
  241. {
  242.   int error=0;
  243.   if (!mp->file)
  244.   {
  245.     fprintf(stderr,
  246.     "safe_mutex: Trying to destroy unitialized mutex at %s, line %dn",
  247.     file, line);
  248.     fflush(stderr);
  249.     abort();
  250.   }
  251.   if (mp->count != 0)
  252.   {
  253.     fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %dn",
  254.     mp->file,mp->line, file, line);
  255.     fflush(stderr);
  256.     abort();
  257.   }
  258. #ifdef __WIN__ 
  259.   pthread_mutex_destroy(&mp->global);
  260.   pthread_mutex_destroy(&mp->mutex);
  261. #else
  262.   if (pthread_mutex_destroy(&mp->global))
  263.     error=1;
  264.   if (pthread_mutex_destroy(&mp->mutex))
  265.     error=1;
  266. #endif
  267.   mp->file= 0; /* Mark destroyed */
  268. #ifdef SAFE_MUTEX_DETECT_DESTROY
  269.   if (mp->info)
  270.   {
  271.     struct st_safe_mutex_info_t *info= mp->info;
  272.     pthread_mutex_lock(&THR_LOCK_mutex);
  273.     if (info->prev)
  274.       info->prev->next = info->next;
  275.     else
  276.       safe_mutex_root = info->next;
  277.     if (info->next)
  278.       info->next->prev = info->prev;
  279.     safe_mutex_count--;
  280.     pthread_mutex_unlock(&THR_LOCK_mutex);
  281.     free(info);
  282.     mp->info= NULL; /* Get crash if double free */
  283.   }
  284. #else
  285.   thread_safe_sub(safe_mutex_count, 1, &THR_LOCK_mutex);
  286. #endif /* SAFE_MUTEX_DETECT_DESTROY */
  287.   return error;
  288. }
  289. /*
  290.   Free global resources and check that all mutex has been destroyed
  291.   SYNOPSIS
  292.     safe_mutex_end()
  293.     file Print errors on this file
  294.   NOTES
  295.     We can't use DBUG_PRINT() here as we have in my_end() disabled
  296.     DBUG handling before calling this function.
  297.    In MySQL one may get one warning for a mutex created in my_thr_init.c
  298.    This is ok, as this thread may not yet have been exited.
  299. */
  300. void safe_mutex_end(FILE *file __attribute__((unused)))
  301. {
  302.   if (!safe_mutex_count) /* safetly */
  303.     pthread_mutex_destroy(&THR_LOCK_mutex);
  304. #ifdef SAFE_MUTEX_DETECT_DESTROY
  305.   if (!file)
  306.     return;
  307.   if (safe_mutex_count)
  308.   {
  309.     fprintf(file, "Warning: Not destroyed mutex: %lun", safe_mutex_count);
  310.     (void) fflush(file);
  311.   }
  312.   {
  313.     struct st_safe_mutex_info_t *ptr;
  314.     for (ptr= safe_mutex_root ; ptr ; ptr= ptr->next)
  315.     {
  316.       fprintf(file, "tMutex initiated at line %4u in '%s'n",
  317.       ptr->init_line, ptr->init_file);
  318.       (void) fflush(file);
  319.     }
  320.   }
  321. #endif /* SAFE_MUTEX_DETECT_DESTROY */
  322. }
  323. #endif /* THREAD && SAFE_MUTEX */