ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

536 lines
12 KiB

  1. //
  2. // Copyright (C) 2009-2012 Artyom Beilis (Tonkikh)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. #define BOOSTER_SOURCE
  9. #include <pthread.h>
  10. #include <booster/thread.h>
  11. #include <booster/system_error.h>
  12. #include <errno.h>
  13. #include <string.h>
  14. #include <booster/auto_ptr_inc.h>
  15. #include <vector>
  16. #include <stack>
  17. #ifdef BOOSTER_POSIX
  18. #include <unistd.h>
  19. #include <fcntl.h>
  20. #include <stdio.h>
  21. #endif
  22. #ifdef BOOSTER_WIN32
  23. # ifndef NOMINMAX
  24. # define NOMINMAX
  25. # endif
  26. # include <windows.h>
  27. #else
  28. # include <unistd.h>
  29. #endif
  30. namespace booster {
  31. typedef function<void()> thread_function_type;
  32. struct thread::data {
  33. pthread_t p;
  34. bool released;
  35. data() : released(false) {}
  36. };
  37. extern "C" void *booster_thread_func(void *p)
  38. {
  39. std::auto_ptr<thread_function_type> caller(reinterpret_cast<thread_function_type *>(p));
  40. try {
  41. thread_function_type &func = *caller;
  42. func();
  43. }
  44. catch(std::exception const &/*e*/) {
  45. /// TODO
  46. }
  47. catch(...) {
  48. /// TODO
  49. }
  50. return 0;
  51. }
  52. thread::thread(function<void()> const &cb) :
  53. d(new thread::data)
  54. {
  55. thread_function_type *ptr = new thread_function_type(cb);
  56. if( ::pthread_create(&d->p,0,booster_thread_func,reinterpret_cast<void *>(ptr)) == 0 ) {
  57. // passed pointer - ownership lost
  58. ptr = 0;
  59. return;
  60. }
  61. else {
  62. // failed to create - delete the object
  63. int err = errno;
  64. delete ptr;
  65. ptr = 0;
  66. throw system::system_error( err,
  67. system::system_category,
  68. "booster::thread: failed to create a thread");
  69. }
  70. }
  71. thread::~thread()
  72. {
  73. detach();
  74. }
  75. void thread::join()
  76. {
  77. if(!d->released) {
  78. pthread_join(d->p,0);
  79. d->released = true;
  80. }
  81. }
  82. void thread::detach()
  83. {
  84. if(!d->released) {
  85. pthread_detach(d->p);
  86. d->released = true;
  87. }
  88. }
  89. unsigned thread::hardware_concurrency()
  90. {
  91. #ifdef BOOSTER_WIN32
  92. SYSTEM_INFO info=SYSTEM_INFO();
  93. GetSystemInfo(&info);
  94. return info.dwNumberOfProcessors;
  95. #else
  96. #ifdef _SC_NPROCESSORS_ONLN
  97. long procs = sysconf(_SC_NPROCESSORS_ONLN);
  98. if(procs < 0)
  99. return 0;
  100. return procs;
  101. #else
  102. return 0;
  103. #endif
  104. #endif
  105. }
  106. struct mutex::data { pthread_mutex_t m; };
  107. mutex::mutex() : d(new data)
  108. {
  109. pthread_mutex_init(&d->m,0);
  110. }
  111. mutex::~mutex()
  112. {
  113. pthread_mutex_destroy(&d->m);
  114. }
  115. void mutex::lock() { pthread_mutex_lock(&d->m); }
  116. void mutex::unlock() { pthread_mutex_unlock(&d->m); }
  117. struct recursive_mutex::data { pthread_mutex_t m; };
  118. recursive_mutex::recursive_mutex() : d(new data)
  119. {
  120. pthread_mutexattr_t a;
  121. pthread_mutexattr_init(&a);
  122. pthread_mutexattr_settype(&a,PTHREAD_MUTEX_RECURSIVE);
  123. pthread_mutex_init(&d->m,&a);
  124. }
  125. recursive_mutex::~recursive_mutex()
  126. {
  127. pthread_mutex_destroy(&d->m);
  128. }
  129. void recursive_mutex::lock() { pthread_mutex_lock(&d->m); }
  130. void recursive_mutex::unlock() { pthread_mutex_unlock(&d->m); }
  131. struct shared_mutex::data { pthread_rwlock_t m; };
  132. shared_mutex::shared_mutex() : d(new data)
  133. {
  134. pthread_rwlock_init(&d->m,0);
  135. }
  136. shared_mutex::~shared_mutex()
  137. {
  138. pthread_rwlock_destroy(&d->m);
  139. }
  140. void shared_mutex::shared_lock() { pthread_rwlock_rdlock(&d->m); }
  141. void shared_mutex::unique_lock() { pthread_rwlock_wrlock(&d->m); }
  142. void shared_mutex::unlock() { pthread_rwlock_unlock(&d->m); }
  143. #if !defined(__APPLE__) && !defined(__NetBSD__)
  144. //
  145. // This is normal implementation
  146. //
  147. // Same as shared mutex under "Most platforms"
  148. //
  149. struct recursive_shared_mutex::data { pthread_rwlock_t m; };
  150. recursive_shared_mutex::recursive_shared_mutex() : d(new data)
  151. {
  152. pthread_rwlock_init(&d->m,0);
  153. }
  154. recursive_shared_mutex::~recursive_shared_mutex()
  155. {
  156. pthread_rwlock_destroy(&d->m);
  157. }
  158. void recursive_shared_mutex::shared_lock() { pthread_rwlock_rdlock(&d->m); }
  159. void recursive_shared_mutex::unique_lock() { pthread_rwlock_wrlock(&d->m); }
  160. void recursive_shared_mutex::unlock() { pthread_rwlock_unlock(&d->m); }
  161. #else // Darwin has broken recursive RW Lock
  162. struct recursive_shared_mutex::data {
  163. thread_specific_ptr<int> k;
  164. pthread_rwlock_t m;
  165. };
  166. namespace {
  167. int &specific_key(thread_specific_ptr<int> &k)
  168. {
  169. int *counter = k.get();
  170. if(!counter) {
  171. counter = new int(0);
  172. k.reset(counter);
  173. }
  174. return *counter;
  175. }
  176. }
  177. recursive_shared_mutex::recursive_shared_mutex() : d(new data)
  178. {
  179. pthread_rwlock_init(&d->m,0);
  180. }
  181. recursive_shared_mutex::~recursive_shared_mutex()
  182. {
  183. pthread_rwlock_destroy(&d->m);
  184. }
  185. void recursive_shared_mutex::shared_lock()
  186. {
  187. int &counter = specific_key(d->k);
  188. if(counter++ == 0)
  189. pthread_rwlock_rdlock(&d->m);
  190. }
  191. void recursive_shared_mutex::unique_lock() {
  192. pthread_rwlock_wrlock(&d->m);
  193. }
  194. void recursive_shared_mutex::unlock() {
  195. int &counter = specific_key(d->k);
  196. if(counter > 1) {
  197. counter --;
  198. return;
  199. }
  200. counter = 0;
  201. pthread_rwlock_unlock(&d->m);
  202. }
  203. #endif
  204. struct condition_variable::data { pthread_cond_t c; };
  205. condition_variable::condition_variable() : d(new data)
  206. {
  207. pthread_cond_init(&d->c,0);
  208. }
  209. condition_variable::~condition_variable()
  210. {
  211. pthread_cond_destroy(&d->c);
  212. }
  213. void condition_variable::notify_one()
  214. {
  215. pthread_cond_signal(&d->c);
  216. }
  217. void condition_variable::notify_all()
  218. {
  219. pthread_cond_broadcast(&d->c);
  220. }
  221. void condition_variable::wait(unique_lock<mutex> &m)
  222. {
  223. pthread_cond_wait(&d->c,&(m.mutex()->d->m));
  224. }
  225. #if !defined(__NetBSD__) && !defined(__CYGWIN__)
  226. //
  227. // Standard implementation pthread_key_t per object
  228. //
  229. namespace details {
  230. extern "C" {
  231. static void booster_pthread_key_destroyer(void *p)
  232. {
  233. if(!p)
  234. return;
  235. delete static_cast<tls_object*>(p);
  236. }
  237. }
  238. class pthread_key : public key {
  239. public:
  240. pthread_key(void (*d)(void *)) : key(d)
  241. {
  242. if(pthread_key_create(&key_,booster_pthread_key_destroyer) != 0) {
  243. throw system::system_error(errno,system::system_category,
  244. "Failed to create thread specific key");
  245. }
  246. }
  247. virtual ~pthread_key()
  248. {
  249. pthread_key_delete(key_);
  250. }
  251. tls_object *get_object()
  252. {
  253. void *p=pthread_getspecific(key_);
  254. if(p)
  255. return static_cast<tls_object*>(p);
  256. tls_object *res = new tls_object(intrusive_ptr<key>(this));
  257. pthread_setspecific(key_,static_cast<void*>(res));
  258. return res;
  259. }
  260. private:
  261. pthread_key_t key_;
  262. };
  263. intrusive_ptr<key> make_key(void (*dtor)(void *))
  264. {
  265. return new pthread_key(dtor);
  266. }
  267. } // details
  268. #else // workaround
  269. //
  270. // There is a workaround for two major cases:
  271. //
  272. // NetBSD: Workaround of failure to allocate and release keys or if there only few pthread_keys avalible, under NetBSD keys are not being released for some reason
  273. //
  274. // Cygwin: deadlock in destructor - call of pthread_key_delete from the destructor given in pthread key itself
  275. //
  276. namespace details {
  277. typedef std::vector<tls_object *> tls_vector;
  278. extern "C" {
  279. static void booster_init_mgr_instance();
  280. static void booster_detail_keys_deleter(void *ptr)
  281. {
  282. if(!ptr)
  283. return;
  284. tls_vector *v=static_cast<tls_vector *>(ptr);
  285. if(!v)
  286. return;
  287. for(size_t i=0;i<v->size();i++)
  288. if((*v)[i])
  289. delete (*v)[i];
  290. delete v;
  291. }
  292. }
  293. class keys_manager {
  294. public:
  295. typedef booster::unique_lock<booster::mutex> guard_type;
  296. static keys_manager &instance()
  297. {
  298. static pthread_once_t once = PTHREAD_ONCE_INIT;
  299. pthread_once(&once,booster_init_mgr_instance);
  300. return *instance_ptr;
  301. }
  302. keys_manager() : key_max_(0)
  303. {
  304. if(pthread_key_create(&key_,booster_detail_keys_deleter)!=0) {
  305. throw system::system_error(errno,system::system_category,
  306. "Failed to create thread specific key");
  307. }
  308. }
  309. int allocate_key()
  310. {
  311. int key;
  312. guard_type g(lock_);
  313. if(reuse_pool_.empty()) {
  314. key = key_max_++;
  315. }
  316. else {
  317. key = reuse_pool_.top();
  318. reuse_pool_.pop();
  319. }
  320. return key;
  321. }
  322. void release_key(int key)
  323. {
  324. try {
  325. guard_type g(lock_);
  326. reuse_pool_.push(key);
  327. }
  328. catch(...) {}
  329. }
  330. tls_vector &get_tls_vector()
  331. {
  332. void *p=pthread_getspecific(key_);
  333. if(!p) {
  334. tls_vector *v = new tls_vector();
  335. pthread_setspecific(key_,v);
  336. return *v;
  337. }
  338. return *static_cast<tls_vector *>(p);
  339. }
  340. static keys_manager *instance_ptr;
  341. private:
  342. booster::mutex lock_;
  343. int key_max_;
  344. std::stack<int> reuse_pool_;
  345. pthread_key_t key_;
  346. };
  347. keys_manager *keys_manager::instance_ptr;
  348. extern "C" {
  349. static void booster_init_mgr_instance()
  350. {
  351. static keys_manager mgr;
  352. keys_manager::instance_ptr = &mgr;
  353. }
  354. }
  355. class unlimited_key : public key {
  356. public:
  357. unlimited_key(void (*d)(void *)) : key(d)
  358. {
  359. id_ = keys_manager::instance().allocate_key();
  360. }
  361. virtual ~unlimited_key()
  362. {
  363. keys_manager::instance().release_key(id_);
  364. }
  365. tls_object *get_object()
  366. {
  367. std::vector<tls_object *> &v=keys_manager::instance().get_tls_vector();
  368. if(v.size() < size_t(id_) + 1) {
  369. v.resize(id_+1,0);
  370. }
  371. tls_object *p=v[id_];
  372. if(p)
  373. return p;
  374. tls_object *res = new tls_object(intrusive_ptr<key>(this));
  375. v[id_] = res;
  376. return res;
  377. }
  378. private:
  379. int id_;
  380. };
  381. intrusive_ptr<key> make_key(void (*dtor)(void *))
  382. {
  383. return new unlimited_key(dtor);
  384. }
  385. } // detail
  386. #endif
  387. #ifdef BOOSTER_POSIX
  388. struct fork_shared_mutex::data {
  389. pthread_rwlock_t lock;
  390. FILE *lock_file;
  391. };
  392. fork_shared_mutex::fork_shared_mutex() : d(new data)
  393. {
  394. pthread_rwlock_init(&d->lock,0);
  395. d->lock_file = tmpfile();
  396. if(!d->lock_file) {
  397. int err=errno;
  398. pthread_rwlock_destroy(&d->lock);
  399. throw system::system_error(err,system::system_category,"fork_shared_mutex:failed to create temporary file");
  400. }
  401. }
  402. fork_shared_mutex::~fork_shared_mutex()
  403. {
  404. // only threads see the lock - it is safe
  405. fclose(d->lock_file);
  406. pthread_rwlock_destroy(&d->lock);
  407. }
  408. bool fork_shared_mutex::try_unique_lock()
  409. {
  410. if(pthread_rwlock_trywrlock(&d->lock)!=0)
  411. return false;
  412. struct flock lock;
  413. memset(&lock,0,sizeof(lock));
  414. lock.l_type=F_WRLCK;
  415. lock.l_whence=SEEK_SET;
  416. int res = 0;
  417. while((res = ::fcntl(fileno(d->lock_file),F_SETLK,&lock))!=0 && errno==EINTR)
  418. ;
  419. if(res == 0)
  420. return true;
  421. int err = errno;
  422. pthread_rwlock_unlock(&d->lock);
  423. if(err == EACCES || err==EAGAIN)
  424. return false;
  425. throw system::system_error(err,system::system_category,"fork_shared_mutex: failed to lock");
  426. }
  427. void fork_shared_mutex::unique_lock()
  428. {
  429. pthread_rwlock_wrlock(&d->lock);
  430. struct flock lock;
  431. memset(&lock,0,sizeof(lock));
  432. lock.l_type=F_WRLCK;
  433. lock.l_whence=SEEK_SET;
  434. int res = 0;
  435. while((res = ::fcntl(fileno(d->lock_file),F_SETLKW,&lock))!=0 && errno==EINTR)
  436. ;
  437. if(res == 0)
  438. return;
  439. int err = errno;
  440. pthread_rwlock_unlock(&d->lock);
  441. throw system::system_error(err,system::system_category,"fork_shared_mutex: failed to lock");
  442. }
  443. bool fork_shared_mutex::try_shared_lock()
  444. {
  445. if(pthread_rwlock_tryrdlock(&d->lock)!=0)
  446. return false;
  447. struct flock lock;
  448. memset(&lock,0,sizeof(lock));
  449. lock.l_type=F_RDLCK;
  450. lock.l_whence=SEEK_SET;
  451. int res = 0;
  452. while((res = ::fcntl(fileno(d->lock_file),F_SETLK,&lock))!=0 && errno==EINTR)
  453. ;
  454. if(res == 0)
  455. return true;
  456. int err = errno;
  457. pthread_rwlock_unlock(&d->lock);
  458. if(err == EACCES || err==EAGAIN)
  459. return false;
  460. throw system::system_error(err,system::system_category,"fork_shared_mutex: failed to lock");
  461. }
  462. void fork_shared_mutex::shared_lock()
  463. {
  464. pthread_rwlock_rdlock(&d->lock);
  465. struct flock lock;
  466. memset(&lock,0,sizeof(lock));
  467. lock.l_type=F_RDLCK;
  468. lock.l_whence=SEEK_SET;
  469. int res = 0;
  470. while((res = ::fcntl(fileno(d->lock_file),F_SETLKW,&lock))!=0 && errno==EINTR)
  471. ;
  472. if(res == 0)
  473. return;
  474. int err = errno;
  475. pthread_rwlock_unlock(&d->lock);
  476. throw system::system_error(err,system::system_category,"fork_shared_mutex: failed to lock");
  477. }
  478. void fork_shared_mutex::unlock()
  479. {
  480. struct flock lock;
  481. memset(&lock,0,sizeof(lock));
  482. lock.l_type=F_UNLCK;
  483. lock.l_whence=SEEK_SET;
  484. int res = 0;
  485. while((res = ::fcntl(fileno(d->lock_file),F_SETLKW,&lock))!=0 && errno==EINTR)
  486. ;
  487. pthread_rwlock_unlock(&d->lock);
  488. }
  489. #endif
  490. } // booster