PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/dep/ACE_wrappers/ace/Token.cpp

https://github.com/MeaNone/mangos
C++ | 545 lines | 353 code | 96 blank | 96 comment | 72 complexity | 15065961d9b424e0fcae8b357fc2a53a MD5 | raw file
  1. // $Id: Token.cpp 80826 2008-03-04 14:51:23Z wotte $
  2. #include "ace/Token.h"
  3. #if !defined (__ACE_INLINE__)
  4. # include "ace/Token.inl"
  5. #endif /* __ACE_INLINE__ */
  6. ACE_RCSID(ace, Token, "$Id: Token.cpp 80826 2008-03-04 14:51:23Z wotte $")
  7. #if defined (ACE_HAS_THREADS)
  8. #include "ace/Thread.h"
  9. #include "ace/Log_Msg.h"
  10. #if defined (ACE_TOKEN_DEBUGGING)
  11. // FUZZ: disable check_for_streams_include
  12. #include "ace/streams.h"
  13. #endif /* ACE_TOKEN_DEBUGGING */
  14. ACE_BEGIN_VERSIONED_NAMESPACE_DECL
  15. ACE_ALLOC_HOOK_DEFINE(ACE_Token)
  16. void
  17. ACE_Token::dump (void) const
  18. {
  19. #if defined (ACE_HAS_DUMP)
  20. ACE_TRACE ("ACE_Token::dump");
  21. ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
  22. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthread = %d"), ACE_Thread::self ()));
  23. // @@ Is there a portable way to do this?
  24. // ACE_DEBUG ((LM_DEBUG, "\nowner_ = %d", (long) this->owner_));
  25. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nowner_ addr = %x"), &this->owner_));
  26. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nwaiters_ = %d"), this->waiters_));
  27. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nin_use_ = %d"), this->in_use_));
  28. ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nnesting level = %d"), this->nesting_level_));
  29. ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
  30. #endif /* ACE_HAS_DUMP */
  31. }
  32. ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
  33. ACE_thread_t t_id)
  34. : next_ (0),
  35. thread_id_ (t_id),
  36. #if defined (ACE_TOKEN_USES_SEMAPHORE)
  37. cv_ (0),
  38. #else
  39. cv_ (m),
  40. #endif /* ACE_TOKEN_USES_SEMAPHORE */
  41. runable_ (0)
  42. {
  43. #if defined (ACE_TOKEN_USES_SEMAPHORE)
  44. ACE_UNUSED_ARG (m);
  45. #endif /* ACE_TOKEN_USES_SEMAPHORE */
  46. ACE_TRACE ("ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry");
  47. }
  48. ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry (ACE_Thread_Mutex &m,
  49. ACE_thread_t t_id,
  50. ACE_Condition_Attributes &attributes)
  51. : next_ (0),
  52. thread_id_ (t_id),
  53. #if defined (ACE_TOKEN_USES_SEMAPHORE)
  54. cv_ (0),
  55. #else
  56. cv_ (m, attributes),
  57. #endif /* ACE_TOKEN_USES_SEMAPHORE */
  58. runable_ (0)
  59. {
  60. #if defined (ACE_TOKEN_USES_SEMAPHORE)
  61. ACE_UNUSED_ARG (m);
  62. ACE_UNUSED_ARG (attributes);
  63. #endif /* ACE_TOKEN_USES_SEMAPHORE */
  64. ACE_TRACE ("ACE_Token::ACE_Token_Queue_Entry::ACE_Token_Queue_Entry");
  65. }
  66. ACE_Token::ACE_Token_Queue::ACE_Token_Queue (void)
  67. : head_ (0),
  68. tail_ (0)
  69. {
  70. ACE_TRACE ("ACE_Token::ACE_Token_Queue::ACE_Token_Queue");
  71. }
  72. //
  73. // Remove an entry from the list. Must be called with locks held.
  74. //
  75. void
  76. ACE_Token::ACE_Token_Queue::remove_entry (ACE_Token::ACE_Token_Queue_Entry *entry)
  77. {
  78. ACE_TRACE ("ACE_Token::ACE_Token_Queue::remove_entry");
  79. ACE_Token_Queue_Entry *curr = 0;
  80. ACE_Token_Queue_Entry *prev = 0;
  81. if (this->head_ == 0)
  82. return;
  83. for (curr = this->head_;
  84. curr != 0 && curr != entry;
  85. curr = curr->next_)
  86. prev = curr;
  87. if (curr == 0)
  88. // Didn't find the entry...
  89. return;
  90. else if (prev == 0)
  91. // Delete at the head.
  92. this->head_ = this->head_->next_;
  93. else
  94. // Delete in the middle.
  95. prev->next_ = curr->next_;
  96. // We need to update the tail of the list if we've deleted the last
  97. // entry.
  98. if (curr->next_ == 0)
  99. this->tail_ = prev;
  100. }
  101. //
  102. // Add an entry into the list. Must be called with locks held.
  103. //
  104. void
  105. ACE_Token::ACE_Token_Queue::insert_entry (ACE_Token::ACE_Token_Queue_Entry &entry,
  106. int requeue_position)
  107. {
  108. if (this->head_ == 0)
  109. {
  110. // No other threads - just add me
  111. this->head_ = &entry;
  112. this->tail_ = &entry;
  113. }
  114. else if (requeue_position == -1)
  115. {
  116. // Insert at the end of the queue.
  117. this->tail_->next_ = &entry;
  118. this->tail_ = &entry;
  119. }
  120. else if (requeue_position == 0)
  121. {
  122. // Insert at head of queue.
  123. entry.next_ = this->head_;
  124. this->head_ = &entry;
  125. }
  126. else
  127. // Insert in the middle of the queue somewhere.
  128. {
  129. // Determine where our thread should go in the queue of waiters.
  130. ACE_Token::ACE_Token_Queue_Entry *insert_after = this->head_;
  131. while (requeue_position-- && insert_after->next_ != 0)
  132. insert_after = insert_after->next_;
  133. entry.next_ = insert_after->next_;
  134. if (entry.next_ == 0)
  135. this->tail_ = &entry;
  136. insert_after->next_ = &entry;
  137. }
  138. }
  139. ACE_Token::ACE_Token (const ACE_TCHAR *name, void *any)
  140. : lock_ (name, (ACE_mutexattr_t *) any),
  141. owner_ (ACE_OS::NULL_thread),
  142. in_use_ (0),
  143. waiters_ (0),
  144. nesting_level_ (0),
  145. attributes_ (USYNC_THREAD),
  146. queueing_strategy_ (FIFO)
  147. {
  148. // ACE_TRACE ("ACE_Token::ACE_Token");
  149. }
  150. ACE_Token::~ACE_Token (void)
  151. {
  152. ACE_TRACE ("ACE_Token::~ACE_Token");
  153. }
  154. int
  155. ACE_Token::shared_acquire (void (*sleep_hook_func)(void *),
  156. void *arg,
  157. ACE_Time_Value *timeout,
  158. ACE_Token_Op_Type op_type)
  159. {
  160. ACE_TRACE ("ACE_Token::shared_acquire");
  161. ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
  162. #if defined (ACE_TOKEN_DEBUGGING)
  163. this->dump ();
  164. #endif /* ACE_TOKEN_DEBUGGING */
  165. ACE_thread_t const thr_id = ACE_Thread::self ();
  166. // Nobody holds the token.
  167. if (!this->in_use_)
  168. {
  169. // Its mine!
  170. this->in_use_ = op_type;
  171. this->owner_ = thr_id;
  172. return 0;
  173. }
  174. //
  175. // Someone already holds the token.
  176. //
  177. // Check if it is us.
  178. if (ACE_OS::thr_equal (thr_id, this->owner_))
  179. {
  180. ++this->nesting_level_;
  181. return 0;
  182. }
  183. // Do a quick check for "polling" behavior.
  184. if (timeout != 0 && timeout->sec () == 0 && timeout->usec () == 0)
  185. {
  186. errno = ETIME;
  187. return -1;
  188. }
  189. //
  190. // We've got to sleep until we get the token.
  191. //
  192. // Which queue we should end up in...
  193. ACE_Token_Queue *queue = (op_type == ACE_Token::READ_TOKEN
  194. ? &this->readers_
  195. : &this->writers_);
  196. // Allocate queue entry on stack. This works since we don't exit
  197. // this method's activation record until we've got the token.
  198. ACE_Token::ACE_Token_Queue_Entry my_entry (this->lock_,
  199. thr_id,
  200. this->attributes_);
  201. queue->insert_entry (my_entry, this->queueing_strategy_);
  202. ++this->waiters_;
  203. // Execute appropriate <sleep_hook> callback. (@@ should these
  204. // methods return a success/failure status, and if so, what should
  205. // we do with it?)
  206. int ret = 0;
  207. if (sleep_hook_func)
  208. {
  209. (*sleep_hook_func) (arg);
  210. ++ret;
  211. }
  212. else
  213. {
  214. // Execute virtual method.
  215. this->sleep_hook ();
  216. ++ret;
  217. }
  218. bool timed_out = false;
  219. bool error = false;
  220. // Sleep until we've got the token (ignore signals).
  221. do
  222. {
  223. int const result = my_entry.wait (timeout, this->lock_);
  224. if (result == -1)
  225. {
  226. // Note, this should obey whatever thread-specific interrupt
  227. // policy is currently in place...
  228. if (errno == EINTR)
  229. continue;
  230. #if defined (ACE_TOKEN_DEBUGGING)
  231. cerr << '(' << ACE_Thread::self () << ')'
  232. << " acquire: "
  233. << (errno == ETIME ? "timed out" : "error occurred")
  234. << endl;
  235. #endif /* ACE_TOKEN_DEBUGGING */
  236. // We come here if a timeout occurs or some serious
  237. // ACE_Condition object error.
  238. if (errno == ETIME)
  239. timed_out = true;
  240. else
  241. error = true;
  242. // Stop the loop.
  243. break;
  244. }
  245. }
  246. while (!ACE_OS::thr_equal (thr_id, this->owner_));
  247. // Do this always and irrespective of the result of wait().
  248. --this->waiters_;
  249. queue->remove_entry (&my_entry);
  250. #if defined (ACE_TOKEN_DEBUGGING)
  251. ACE_DEBUG ((LM_DEBUG, "(%t) ACE_Token::shared_acquire (UNBLOCKED)\n"));
  252. #endif /* ACE_TOKEN_DEBUGGING */
  253. // If timeout occured
  254. if (timed_out)
  255. {
  256. // This thread was still selected to own the token.
  257. if (my_entry.runable_)
  258. {
  259. // Wakeup next waiter since this thread timed out.
  260. this->wakeup_next_waiter ();
  261. }
  262. // Return error.
  263. return -1;
  264. }
  265. else if (error)
  266. {
  267. // Return error.
  268. return -1;
  269. }
  270. // If this is a normal wakeup, this thread should be runnable.
  271. ACE_ASSERT (my_entry.runable_);
  272. return ret;
  273. }
  274. // By default this is a no-op.
  275. /* virtual */
  276. void
  277. ACE_Token::sleep_hook (void)
  278. {
  279. ACE_TRACE ("ACE_Token::sleep_hook");
  280. }
  281. int
  282. ACE_Token::acquire (ACE_Time_Value *timeout)
  283. {
  284. ACE_TRACE ("ACE_Token::acquire");
  285. return this->shared_acquire (0, 0, timeout, ACE_Token::WRITE_TOKEN);
  286. }
  287. // Acquire the token, sleeping until it is obtained or until <timeout>
  288. // expires.
  289. int
  290. ACE_Token::acquire (void (*sleep_hook_func)(void *),
  291. void *arg,
  292. ACE_Time_Value *timeout)
  293. {
  294. ACE_TRACE ("ACE_Token::acquire");
  295. return this->shared_acquire (sleep_hook_func, arg, timeout, ACE_Token::WRITE_TOKEN);
  296. }
  297. // Try to renew the token.
  298. int
  299. ACE_Token::renew (int requeue_position,
  300. ACE_Time_Value *timeout)
  301. {
  302. ACE_TRACE ("ACE_Token::renew");
  303. ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
  304. #if defined (ACE_TOKEN_DEBUGGING)
  305. this->dump ();
  306. #endif /* ACE_TOKEN_DEBUGGING */
  307. // ACE_ASSERT (ACE_OS::thr_equal (ACE_Thread::self (), this->owner_));
  308. // Check to see if there are any waiters worth giving up the lock
  309. // for.
  310. // If no writers and either we are a writer or there are no readers.
  311. if (this->writers_.head_ == 0 &&
  312. (this->in_use_ == ACE_Token::WRITE_TOKEN ||
  313. this->readers_.head_ == 0))
  314. // Immediate return.
  315. return 0;
  316. // We've got to sleep until we get the token again.
  317. // Determine which queue should this thread go to.
  318. ACE_Token::ACE_Token_Queue *this_threads_queue =
  319. this->in_use_ == ACE_Token::READ_TOKEN ?
  320. &this->readers_ : &this->writers_;
  321. ACE_Token::ACE_Token_Queue_Entry my_entry (this->lock_,
  322. this->owner_);
  323. this_threads_queue->insert_entry (my_entry,
  324. // if requeue_position == 0 then we want to go next,
  325. // otherwise use the queueing strategy, which might also
  326. // happen to be 0.
  327. requeue_position == 0 ? 0 : this->queueing_strategy_);
  328. ++this->waiters_;
  329. // Remember nesting level...
  330. int const save_nesting_level_ = this->nesting_level_;
  331. // Reset state for new owner.
  332. this->nesting_level_ = 0;
  333. // Wakeup waiter.
  334. this->wakeup_next_waiter ();
  335. bool timed_out = false;
  336. bool error = false;
  337. // Sleep until we've got the token (ignore signals).
  338. do
  339. {
  340. int const result = my_entry.wait (timeout, this->lock_);
  341. if (result == -1)
  342. {
  343. // Note, this should obey whatever thread-specific interrupt
  344. // policy is currently in place...
  345. if (errno == EINTR)
  346. continue;
  347. #if defined (ACE_TOKEN_DEBUGGING)
  348. cerr << '(' << ACE_Thread::self () << ')'
  349. << " renew: "
  350. << (errno == ETIME ? "timed out" : "error occurred")
  351. << endl;
  352. #endif /* ACE_TOKEN_DEBUGGING */
  353. // We come here if a timeout occurs or some serious
  354. // ACE_Condition object error.
  355. if (errno == ETIME)
  356. timed_out = true;
  357. else
  358. error = true;
  359. // Stop the loop.
  360. break;
  361. }
  362. }
  363. while (!ACE_OS::thr_equal (my_entry.thread_id_, this->owner_));
  364. // Do this always and irrespective of the result of wait().
  365. --this->waiters_;
  366. this_threads_queue->remove_entry (&my_entry);
  367. #if defined (ACE_TOKEN_DEBUGGING)
  368. ACE_DEBUG ((LM_DEBUG, "(%t) ACE_Token::renew (UNBLOCKED)\n"));
  369. #endif /* ACE_TOKEN_DEBUGGING */
  370. // If timeout occured
  371. if (timed_out)
  372. {
  373. // This thread was still selected to own the token.
  374. if (my_entry.runable_)
  375. {
  376. // Wakeup next waiter since this thread timed out.
  377. this->wakeup_next_waiter ();
  378. }
  379. // Return error.
  380. return -1;
  381. }
  382. else if (error)
  383. {
  384. // Return error.
  385. return -1;
  386. }
  387. // If this is a normal wakeup, this thread should be runnable.
  388. ACE_ASSERT (my_entry.runable_);
  389. // Reinstate nesting level.
  390. this->nesting_level_ = save_nesting_level_;
  391. return 0;
  392. }
  393. // Release the current holder of the token (which had
  394. // better be the caller's thread!).
  395. int
  396. ACE_Token::release (void)
  397. {
  398. ACE_TRACE ("ACE_Token::release");
  399. ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
  400. #if defined (ACE_TOKEN_DEBUGGING)
  401. this->dump ();
  402. #endif /* ACE_TOKEN_DEBUGGING */
  403. // Nested release...
  404. if (this->nesting_level_ > 0)
  405. --this->nesting_level_;
  406. else
  407. {
  408. //
  409. // Regular release...
  410. //
  411. // Wakeup waiter.
  412. this->wakeup_next_waiter ();
  413. }
  414. return 0;
  415. }
  416. void
  417. ACE_Token::wakeup_next_waiter (void)
  418. {
  419. ACE_TRACE ("ACE_Token::wakeup_next_waiter");
  420. // Reset state for new owner.
  421. this->owner_ = ACE_OS::NULL_thread;
  422. this->in_use_ = 0;
  423. // Any waiters...
  424. if (this->writers_.head_ == 0 &&
  425. this->readers_.head_ == 0)
  426. {
  427. // No more waiters...
  428. return;
  429. }
  430. // Wakeup next waiter.
  431. ACE_Token_Queue *queue = 0;
  432. // Writer threads get priority to run first.
  433. if (this->writers_.head_ != 0)
  434. {
  435. this->in_use_ = ACE_Token::WRITE_TOKEN;
  436. queue = &this->writers_;
  437. }
  438. else
  439. {
  440. this->in_use_ = ACE_Token::READ_TOKEN;
  441. queue = &this->readers_;
  442. }
  443. // Wake up waiter and make it runable.
  444. queue->head_->runable_ = 1;
  445. queue->head_->signal ();
  446. this->owner_ = queue->head_->thread_id_;
  447. }
  448. ACE_END_VERSIONED_NAMESPACE_DECL
  449. #endif /* ACE_HAS_THREADS */