SBtrdMutex.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:14k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /* SBtrdMutex, classes for managing various types of mutexes */
  2. /****************License************************************************
  3.  * Vocalocity OpenVXI
  4.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *  
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  19.  * registered trademarks of Vocalocity, Inc. 
  20.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  21.  * by Vocalocity.
  22.  ***********************************************************************/
  23. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  24. #define SBTRDUTIL_EXPORTS
  25. #include "SBtrdMutex.hpp"             // Header for this class
  26. #include <stdio.h>
  27. #include <limits.h>                   // For ULONG_MAX
  28. #include "VXIlog.h"                   // For logging
  29. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  30. // Destructor
  31. SBTRDUTIL_API_CLASS SBtrdMutex::~SBtrdMutex( )
  32. {
  33.   if ( _name )
  34.     delete [] _name;
  35.   if ( _mutex )
  36.     VXItrdMutexDestroy (&_mutex);
  37. }
  38. // Creation method
  39. SBTRDUTIL_API_CLASS VXItrdResult 
  40. SBtrdMutex::Create (const wchar_t *name)
  41. {
  42.   if (( ! name ) || ( ! name[0] ))
  43.     return VXItrd_RESULT_INVALID_ARGUMENT;
  44.   
  45.   // Save a copy of the name
  46.   size_t len = wcslen (name);
  47.   _name = new wchar_t[len];
  48.   if ( ! _name )
  49.     return VXItrd_RESULT_OUT_OF_MEMORY;
  50.   
  51.   // Create the mutex
  52.   return VXItrdMutexCreate (&_mutex);
  53. }
  54. // Lock and unlock the mutex. Declared as const so that users can
  55. // lock/unlock for read access within const methods.  NOTE: Not
  56. // inlined, otherwise users of SBtrdUtil would have to manually link
  57. // to SBtrd directly instead of just requiring the former.
  58. SBTRDUTIL_API_CLASS VXItrdResult SBtrdMutex::Lock( ) const 
  59.   return VXItrdMutexLock (_mutex);
  60. }
  61. SBTRDUTIL_API_CLASS VXItrdResult SBtrdMutex::Unlock( ) const
  62.   return VXItrdMutexUnlock (_mutex);
  63. }
  64. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  65. // CrossThreadMutex creation method
  66. SBTRDUTIL_API_CLASS VXItrdResult
  67. SBtrdReaderWriterMutex::CrossThreadMutex::Create (const wchar_t *name)
  68. {
  69.   VXItrdResult rc = SBtrdMutex::Create (name);
  70.   if ( rc == VXItrd_RESULT_SUCCESS )
  71.     rc = VXItrdTimerCreate (&_timer);
  72.   return rc;
  73. }
  74. // CrossThreadMutex lock method
  75. SBTRDUTIL_API_CLASS VXItrdResult
  76. SBtrdReaderWriterMutex::CrossThreadMutex::Lock( ) const
  77. {
  78.   VXItrdResult rc;
  79.   if ( (rc = SBtrdMutex::Lock( )) == VXItrd_RESULT_SUCCESS ) {
  80.     while (( _locked ) && 
  81.    ( (rc = VXItrdTimerSleep (_timer, INT_MAX, NULL)) ==
  82.      VXItrd_RESULT_SUCCESS ))
  83.       ; // keep waiting
  84.     
  85.     if ( rc == VXItrd_RESULT_SUCCESS ) {
  86.       CrossThreadMutex *pThis = const_cast<CrossThreadMutex *>(this);
  87.       pThis->_locked = true;
  88.     }
  89.     
  90.     if ( SBtrdMutex::Unlock( ) != VXItrd_RESULT_SUCCESS )
  91.       rc = VXItrd_RESULT_SYSTEM_ERROR;
  92.   }
  93.   return rc;
  94. }
  95. // CrossThreadMutex unlock method
  96. SBTRDUTIL_API_CLASS VXItrdResult
  97. SBtrdReaderWriterMutex::CrossThreadMutex::Unlock( ) const
  98. {
  99.   if ( ! _locked )
  100.     return VXItrd_RESULT_FATAL_ERROR;
  101.   CrossThreadMutex *pThis = const_cast<CrossThreadMutex *>(this);
  102.   pThis->_locked = false;
  103.   return VXItrdTimerWake (_timer);
  104. }
  105. // Creation method
  106. SBTRDUTIL_API_CLASS VXItrdResult 
  107. SBtrdReaderWriterMutex::Create (const wchar_t *name)
  108. {
  109.   // Need five underlying mutex. We'll use the mutex from our base
  110.   // class for the write lock.
  111.   VXItrdResult rc;
  112.   if (( (rc = SBtrdMutex::Create (name)) != VXItrd_RESULT_SUCCESS ) ||
  113.       ( (rc = _readerMutex.Create (name)) != VXItrd_RESULT_SUCCESS ) ||
  114.       ( (rc = _writerMutex.Create (name)) != VXItrd_RESULT_SUCCESS ) ||
  115.       ( (rc = _readerCountMutex.Create (name)) != VXItrd_RESULT_SUCCESS ) ||
  116.       ( (rc = _writerCountMutex.Create (name)) != VXItrd_RESULT_SUCCESS )) {
  117.     Error (0, NULL);
  118.     return rc;
  119.   }
  120.   return VXItrd_RESULT_SUCCESS;
  121. }
  122. // Obtain write access
  123. SBTRDUTIL_API_CLASS VXItrdResult SBtrdReaderWriterMutex::Lock( ) const
  124. {
  125.   VXItrdResult rc = VXItrd_RESULT_SUCCESS;
  126. #ifdef FAKE_READER_WRITER_MUTEX
  127.   rc = SBtrdMutex::Lock( );
  128. #else
  129.   Diag (0, L"SBtrdReaderWriterMutex::Lock", L"enter: rwMutex 0x%p", this);
  130.   // Get the writer lock, writers have preference
  131.   if ( _writerCountMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  132.     Error (1, NULL);
  133.     return VXItrd_RESULT_SYSTEM_ERROR;
  134.   }
  135.   if ( _writerCount < ULONG_MAX ) {
  136.     SBtrdReaderWriterMutex *pThis = const_cast<SBtrdReaderWriterMutex *>(this);
  137.     ++(pThis->_writerCount);
  138.     if ( _writerCount == 1 ) {
  139.       Diag (0, L"SBtrdReaderWriterMutex::Lock", L"first writer 0x%p", this);
  140.       if ( _readerMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  141. Error (2, NULL);
  142. rc = VXItrd_RESULT_SYSTEM_ERROR;
  143.       }
  144.     }
  145.   } else {
  146.     Error (3, NULL);
  147.     rc = VXItrd_RESULT_FATAL_ERROR;
  148.   }
  149.   if ( _writerCountMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  150.     Error (40, NULL);
  151.     rc = VXItrd_RESULT_SYSTEM_ERROR;
  152.   } else if (( rc == VXItrd_RESULT_SUCCESS ) &&
  153.      ( _writerMutex.Lock( ) != VXItrd_RESULT_SUCCESS )) {
  154.     Error (4, NULL);
  155.     rc = VXItrd_RESULT_SYSTEM_ERROR;
  156.   }
  157.   Diag (0, L"SBtrdReaderWriterMutex::Lock", L"exit: rwMutex 0x%p", this);
  158. #endif
  159.   return rc;
  160. }
  161. // Release write access
  162. SBTRDUTIL_API_CLASS VXItrdResult SBtrdReaderWriterMutex::Unlock( ) const
  163. {
  164.   VXItrdResult rc = VXItrd_RESULT_SUCCESS;
  165. #ifdef FAKE_READER_WRITER_MUTEX
  166.   rc = SBtrdMutex::Unlock( );
  167. #else
  168.   Diag (0, L"SBtrdReaderWriterMutex::Unlock", L"enter: rwMutex 0x%p", this);
  169.   // Release the writer lock, preserve writer preference
  170.   if (( _writerMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) ||
  171.       ( _writerCountMutex.Lock( ) != VXItrd_RESULT_SUCCESS )) {
  172.     Error (5, NULL);
  173.     return VXItrd_RESULT_SYSTEM_ERROR;
  174.   }
  175.   if ( _writerCount > 0 ) {
  176.     SBtrdReaderWriterMutex *pThis = const_cast<SBtrdReaderWriterMutex *>(this);
  177.     --(pThis->_writerCount);
  178.     if ( _writerCount == 0 ) {
  179.       Diag (0, L"SBtrdReaderWriterMutex::Unlock", L"last writer 0x%p", this);
  180.       if ( _readerMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  181. Error (6, NULL);
  182. rc = VXItrd_RESULT_SYSTEM_ERROR;
  183.       }
  184.     }
  185.   } else {
  186.     Error (7, NULL);
  187.     rc = VXItrd_RESULT_FATAL_ERROR;
  188.   }
  189.   
  190.   if ( _writerCountMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  191.     Error (8, NULL);
  192.     rc = VXItrd_RESULT_SYSTEM_ERROR;
  193.   }
  194.   Diag (0, L"SBtrdReaderWriterMutex::Unlock", L"exit: rwMutex 0x%p", this);
  195. #endif
  196.   return rc;
  197. }
  198. // Obtain read access. Declared as const so that users can lock/unlock
  199. // for read access within const methods.
  200. SBTRDUTIL_API_CLASS VXItrdResult 
  201. SBtrdReaderWriterMutex::StartRead( ) const
  202. {
  203.   VXItrdResult rc = VXItrd_RESULT_SUCCESS;
  204. #ifdef FAKE_READER_WRITER_MUTEX
  205.   rc = SBtrdMutex::Lock( );
  206. #else
  207.   Diag (0, L"SBtrdReaderWriterMutex::StartRead", L"enter: rwMutex 0x%p", this);
  208.   // Wait on mutexes, giving writers preference
  209.   if (( SBtrdMutex::Lock( ) != VXItrd_RESULT_SUCCESS ) ||
  210.       ( _readerMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) ||
  211.       ( _readerCountMutex.Lock( ) != VXItrd_RESULT_SUCCESS )) {
  212.     Error (9, NULL);
  213.     return VXItrd_RESULT_SYSTEM_ERROR;
  214.   }
  215.   
  216.   if ( _readerCount < ULONG_MAX ) {
  217.     SBtrdReaderWriterMutex *pThis = const_cast<SBtrdReaderWriterMutex *>(this);
  218.     ++(pThis->_readerCount);
  219.     if ( _readerCount == 1 ) {
  220.       Diag (0, L"SBtrdReaderWriterMutex::StartRead",L"first reader 0x%p",this);
  221.       if ( _writerMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  222. Error (10, NULL);
  223. rc = VXItrd_RESULT_SYSTEM_ERROR;
  224.       }
  225.     }
  226.   } else {
  227.     Error (11, NULL);
  228.     rc = VXItrd_RESULT_FATAL_ERROR;
  229.   }
  230.   
  231.   if (( _readerCountMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) ||
  232.       ( _readerMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) ||
  233.       ( SBtrdMutex::Unlock( ) != VXItrd_RESULT_SUCCESS )) {
  234.     Error (12, NULL);
  235.     rc = VXItrd_RESULT_SYSTEM_ERROR;
  236.   }
  237.   
  238.   Diag (0, L"SBtrdReaderWriterMutex::StartRead", L"exit: rwMutex 0x%p", this);
  239. #endif
  240.   return rc;
  241. }
  242. // Release read access. Declared as const so that users can lock/unlock
  243. // for read access within const methods.
  244. SBTRDUTIL_API_CLASS VXItrdResult 
  245. SBtrdReaderWriterMutex::EndRead( ) const
  246. {
  247.   VXItrdResult rc = VXItrd_RESULT_SUCCESS;
  248. #ifdef FAKE_READER_WRITER_MUTEX
  249.   rc = SBtrdMutex::Unlock( );
  250. #else
  251.   Diag (0, L"SBtrdReaderWriterMutex::EndRead", L"enter: rwMutex 0x%p", this);
  252.   // Release mutex, preserving writer preference
  253.   if ( _readerCountMutex.Lock( ) != VXItrd_RESULT_SUCCESS ) {
  254.     Error (13, NULL);
  255.     return VXItrd_RESULT_SYSTEM_ERROR;
  256.   }
  257.   if ( _readerCount > 0 ) {
  258.     SBtrdReaderWriterMutex *pThis = const_cast<SBtrdReaderWriterMutex *>(this);
  259.     --(pThis->_readerCount);
  260.     if ( _readerCount == 0 ) {
  261.       Diag (0, L"SBtrdReaderWriterMutex::EndRead", L"last reader 0x%p", this);
  262.       if ( _writerMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  263. Error (14, NULL);
  264. rc = VXItrd_RESULT_SYSTEM_ERROR;
  265.       }
  266.     }
  267.   } else {
  268.     Error (15, NULL);
  269.     rc = VXItrd_RESULT_FATAL_ERROR;
  270.   }
  271.   
  272.   if ( _readerCountMutex.Unlock( ) != VXItrd_RESULT_SUCCESS ) {
  273.     Error (16, NULL);
  274.     rc = VXItrd_RESULT_SYSTEM_ERROR;
  275.   }
  276.   Diag (0, L"SBtrdReaderWriterMutex::EndRead", L"exit: rwMutex 0x%p", this);
  277. #endif
  278.   return rc;
  279. }
  280. // Error logging
  281. SBTRDUTIL_API_CLASS void
  282. SBtrdReaderWriterMutex::Error (VXIunsigned errorID, const VXIchar *format,
  283.        ...) const
  284. {
  285.   if ( _log ) {
  286.     if ( format ) {
  287.       va_list arguments;
  288.       va_start(arguments, format);
  289.       (*_log->VError)(_log, COMPANY_DOMAIN L"SBtrdUtil", errorID, format,
  290.       arguments);
  291.       va_end(arguments);
  292.     } else {
  293.       (*_log->Error)(_log, COMPANY_DOMAIN L"SBtrdUtil", errorID, NULL);
  294.     }
  295.   }  
  296. }
  297. // Diagnostic logging
  298. SBTRDUTIL_API_CLASS void
  299. SBtrdReaderWriterMutex::Diag (VXIunsigned tag, const VXIchar *subtag, 
  300.       const VXIchar *format, ...) const
  301. {
  302.   if ( _log ) {
  303.     if ( format ) {
  304.       va_list arguments;
  305.       va_start(arguments, format);
  306.       (*_log->VDiagnostic)(_log, tag + _diagTagBase, subtag, format, 
  307.    arguments);
  308.       va_end(arguments);
  309.     } else {
  310.       (*_log->Diagnostic)(_log, tag + _diagTagBase, subtag, NULL);
  311.     }
  312. #if 0
  313.   } else {
  314.     VXIchar temp[1024];
  315.     va_list arguments;
  316.     va_start(arguments, format);
  317.     wcscpy (temp, subtag);
  318.     wcscat (temp, L"|");
  319.     wcscat (temp, format);
  320.     wcscat (temp, L"n");
  321.     vfwprintf(stderr, temp, arguments);
  322.     va_end(arguments);
  323. #endif
  324.   }
  325. }
  326. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  327. // Creation method, the name is simply for logging purposes
  328. SBTRDUTIL_API_CLASS VXItrdResult 
  329. SBtrdMutexPool::Create (const wchar_t *name, unsigned int size)
  330. {
  331.   if (( ! name ) || ( ! name[0] ) || ( size == 0 ))
  332.     return VXItrd_RESULT_INVALID_ARGUMENT;
  333.   // Create the mutex pool
  334.   _pool = new SBtrdMutex [size];
  335.   if ( ! _pool )
  336.     return VXItrd_RESULT_OUT_OF_MEMORY;
  337.   // Initialize the mutexes
  338.   VXItrdResult rc = VXItrd_RESULT_SUCCESS;
  339.   for (unsigned int i = 0; i < size; i++) {
  340.     if ( (rc = _pool[i].Create (name)) != VXItrd_RESULT_SUCCESS ) {
  341.       delete [] _pool;
  342.       return rc;
  343.     }
  344.   }
  345.   
  346.   _size = size;
  347.   return VXItrd_RESULT_SUCCESS;
  348. }
  349. // Obtain a mutex out of the pool, the mutex pool continues to own
  350. // this mutex so you must not destroy it, and this mutex may be
  351. // returned multiple times
  352. SBTRDUTIL_API_CLASS SBtrdMutex *SBtrdMutexPool::GetMutex( )
  353. {
  354.   if ( _pool == NULL )
  355.     return NULL;
  356.   // Lock using mutex 0
  357.   if ( _pool[0].Lock( ) != VXItrd_RESULT_SUCCESS )
  358.     return NULL;
  359.   // Retrieve the appropriate mutex and increment the index for
  360.   // round-robin allocation
  361.   SBtrdMutex *mutex = &_pool[_curIndex];
  362.   if ( _curIndex < _size - 1 )
  363.     _curIndex++;
  364.   else
  365.     _curIndex = 0;
  366.   // Unlock using mutex 0
  367.   if ( _pool[0].Unlock( ) != VXItrd_RESULT_SUCCESS )
  368.     return NULL;
  369.   return mutex;
  370. }
  371. // -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8
  372. // Creation method, the name is simply for logging purposes
  373. SBTRDUTIL_API_CLASS VXItrdResult 
  374. SBtrdReaderWriterMutexPool::Create (const wchar_t *name, unsigned int size)
  375. {
  376.   if (( ! name ) || ( ! name[0] ) || ( size == 0 ))
  377.     return VXItrd_RESULT_INVALID_ARGUMENT;
  378.   // Create the allocation mutex
  379.   _allocationMutex = new SBtrdMutex;
  380.   if ( ! _allocationMutex )
  381.     return VXItrd_RESULT_OUT_OF_MEMORY;
  382.   
  383.   // Create the mutex pool
  384.   _pool = new SBtrdReaderWriterMutex [size];
  385.   if ( ! _pool )
  386.     return VXItrd_RESULT_OUT_OF_MEMORY;
  387.   // Initialize the mutexes
  388.   VXItrdResult rc = VXItrd_RESULT_SUCCESS;
  389.   if ( (rc = _allocationMutex->Create (name)) != VXItrd_RESULT_SUCCESS ) {
  390.     delete _allocationMutex;
  391.     return rc;
  392.   }
  393.   for (unsigned int i = 0; i < size; i++) {
  394.     if ( (rc = _pool[i].Create (name)) != VXItrd_RESULT_SUCCESS ) {
  395.       delete [] _pool;
  396.       return rc;
  397.     }
  398.   }
  399.   
  400.   _size = size;
  401.   return VXItrd_RESULT_SUCCESS;
  402. }
  403. // Obtain a mutex out of the pool, the mutex pool continues to own
  404. // this mutex so you must not destroy it, and this mutex may be
  405. // returned multiple times
  406. SBTRDUTIL_API_CLASS SBtrdReaderWriterMutex *
  407. SBtrdReaderWriterMutexPool::GetMutex( )
  408. {
  409.   if ( _pool == NULL )
  410.     return NULL;
  411.   // Lock for exlusive access
  412.   if ( _allocationMutex->Lock( ) != VXItrd_RESULT_SUCCESS )
  413.     return NULL;
  414.   // Retrieve the appropriate mutex and increment the index for
  415.   // round-robin allocation
  416.   SBtrdReaderWriterMutex *mutex = &_pool[_curIndex];
  417.   if ( _curIndex < _size - 1 )
  418.     _curIndex++;
  419.   else
  420.     _curIndex = 0;
  421.   // Unlock
  422.   if ( _allocationMutex->Unlock( ) != VXItrd_RESULT_SUCCESS )
  423.     return NULL;
  424.   return mutex;
  425. }