token.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // token.h -- lock tokens for gold -*- C++ -*-
  2. // Copyright (C) 2006-2022 Free Software Foundation, Inc.
  3. // Written by Ian Lance Taylor <iant@google.com>.
  4. // This file is part of gold.
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. // MA 02110-1301, USA.
  17. #ifndef GOLD_TOKEN_H
  18. #define GOLD_TOKEN_H
  19. namespace gold
  20. {
  21. class Condvar;
  22. class Task;
  23. // A list of Tasks, managed through the next_locked_ field in the
  24. // class Task. We define this class here because we need it in
  25. // Task_token.
  26. class Task_list
  27. {
  28. public:
  29. Task_list()
  30. : head_(NULL), tail_(NULL)
  31. { }
  32. ~Task_list()
  33. { gold_assert(this->head_ == NULL && this->tail_ == NULL); }
  34. // Return whether the list is empty.
  35. bool
  36. empty() const
  37. { return this->head_ == NULL; }
  38. // Add T to the head of the list.
  39. void
  40. push_front(Task* t);
  41. // Add T to the end of the list.
  42. void
  43. push_back(Task* t);
  44. // Remove the first Task on the list and return it. Return NULL if
  45. // the list is empty.
  46. Task*
  47. pop_front();
  48. private:
  49. // The start of the list. NULL if the list is empty.
  50. Task* head_;
  51. // The end of the list. NULL if the list is empty.
  52. Task* tail_;
  53. };
  54. // We support two basic types of locks, which are both implemented
  55. // using the single class Task_token.
  56. // A write lock may be held by a single Task at a time. This is used
  57. // to control access to a single shared resource such as an Object.
  58. // A blocker is used to indicate that a Task A must be run after some
  59. // set of Tasks B. For each of the Tasks B, we increment the blocker
  60. // when the Task is created, and decrement it when the Task is
  61. // completed. When the count goes to 0, the task A is ready to run.
  62. // There are no shared read locks. We always read and write objects
  63. // in predictable patterns. The purpose of the locks is to permit
  64. // some flexibility for the threading system, for cases where the
  65. // execution order does not matter.
  66. // These tokens are only manipulated when the workqueue lock is held
  67. // or when they are first created. They do not require any locking
  68. // themselves.
  69. class Task_token
  70. {
  71. public:
  72. Task_token(bool is_blocker)
  73. : is_blocker_(is_blocker), blockers_(0), writer_(NULL), waiting_()
  74. { }
  75. ~Task_token()
  76. {
  77. gold_assert(this->blockers_ == 0);
  78. gold_assert(this->writer_ == NULL);
  79. }
  80. // Return whether this is a blocker.
  81. bool
  82. is_blocker() const
  83. { return this->is_blocker_; }
  84. // A write lock token uses these methods.
  85. // Is the token writable?
  86. bool
  87. is_writable() const
  88. {
  89. gold_assert(!this->is_blocker_);
  90. return this->writer_ == NULL;
  91. }
  92. // Add the task as the token's writer (there may only be one
  93. // writer).
  94. void
  95. add_writer(const Task* t)
  96. {
  97. gold_assert(!this->is_blocker_ && this->writer_ == NULL);
  98. this->writer_ = t;
  99. }
  100. // Remove the task as the token's writer.
  101. void
  102. remove_writer(const Task* t)
  103. {
  104. gold_assert(!this->is_blocker_ && this->writer_ == t);
  105. this->writer_ = NULL;
  106. }
  107. // A blocker token uses these methods.
  108. // Add a blocker to the token.
  109. void
  110. add_blocker()
  111. {
  112. gold_assert(this->is_blocker_);
  113. ++this->blockers_;
  114. this->writer_ = NULL;
  115. }
  116. // Add some number of blockers to the token.
  117. void
  118. add_blockers(int c)
  119. {
  120. gold_assert(this->is_blocker_);
  121. this->blockers_ += c;
  122. this->writer_ = NULL;
  123. }
  124. // Remove a blocker from the token. Returns true if block count
  125. // drops to zero.
  126. bool
  127. remove_blocker()
  128. {
  129. gold_assert(this->is_blocker_ && this->blockers_ > 0);
  130. --this->blockers_;
  131. this->writer_ = NULL;
  132. return this->blockers_ == 0;
  133. }
  134. // Is the token currently blocked?
  135. bool
  136. is_blocked() const
  137. {
  138. gold_assert(this->is_blocker_);
  139. return this->blockers_ > 0;
  140. }
  141. // Both blocker and write lock tokens use these methods.
  142. // Add T to the list of tasks waiting for this token to be released.
  143. void
  144. add_waiting(Task* t)
  145. { this->waiting_.push_back(t); }
  146. // Add T to the front of the list of tasks waiting for this token to
  147. // be released.
  148. void
  149. add_waiting_front(Task* t)
  150. { this->waiting_.push_front(t); }
  151. // Remove the first Task waiting for this token to be released, and
  152. // return it. Return NULL if no Tasks are waiting.
  153. Task*
  154. remove_first_waiting()
  155. { return this->waiting_.pop_front(); }
  156. private:
  157. // It makes no sense to copy these.
  158. Task_token(const Task_token&);
  159. Task_token& operator=(const Task_token&);
  160. // Whether this is a blocker token.
  161. bool is_blocker_;
  162. // The number of blockers.
  163. int blockers_;
  164. // The single writer.
  165. const Task* writer_;
  166. // The list of Tasks waiting for this token to be released.
  167. Task_list waiting_;
  168. };
  169. // In order to support tokens more reliably, we provide objects which
  170. // handle them using RAII.
  171. // RAII class to get a write lock on a token. This requires
  172. // specifying the task which is doing the lock.
  173. class Task_write_token
  174. {
  175. public:
  176. Task_write_token(Task_token* token, const Task* task)
  177. : token_(token), task_(task)
  178. { this->token_->add_writer(this->task_); }
  179. ~Task_write_token()
  180. { this->token_->remove_writer(this->task_); }
  181. private:
  182. Task_write_token(const Task_write_token&);
  183. Task_write_token& operator=(const Task_write_token&);
  184. Task_token* token_;
  185. const Task* task_;
  186. };
  187. // RAII class for a blocker.
  188. class Task_block_token
  189. {
  190. public:
  191. // The blocker count must be incremented when the task is created.
  192. // This object is created when the task is run, so we don't do
  193. // anything in the constructor.
  194. Task_block_token(Task_token* token)
  195. : token_(token)
  196. { gold_assert(this->token_->is_blocked()); }
  197. ~Task_block_token()
  198. { this->token_->remove_blocker(); }
  199. private:
  200. Task_block_token(const Task_block_token&);
  201. Task_block_token& operator=(const Task_block_token&);
  202. Task_token* token_;
  203. };
  204. // An object which implements an RAII lock for any object which
  205. // supports lock and unlock methods.
  206. template<typename Obj>
  207. class Task_lock_obj
  208. {
  209. public:
  210. Task_lock_obj(const Task* task, Obj* obj)
  211. : task_(task), obj_(obj)
  212. { this->obj_->lock(task); }
  213. ~Task_lock_obj()
  214. { this->obj_->unlock(this->task_); }
  215. private:
  216. Task_lock_obj(const Task_lock_obj&);
  217. Task_lock_obj& operator=(const Task_lock_obj&);
  218. const Task* task_;
  219. Obj* obj_;
  220. };
  221. // A class which holds the set of Task_tokens which must be locked for
  222. // a Task. No Task requires more than four Task_tokens, so we set
  223. // that as a limit.
  224. class Task_locker
  225. {
  226. public:
  227. static const int max_task_count = 4;
  228. Task_locker()
  229. : count_(0)
  230. { }
  231. ~Task_locker()
  232. { }
  233. // Clear the locker.
  234. void
  235. clear()
  236. { this->count_ = 0; }
  237. // Add a token to the locker.
  238. void
  239. add(Task* t, Task_token* token)
  240. {
  241. gold_assert(this->count_ < max_task_count);
  242. this->tokens_[this->count_] = token;
  243. ++this->count_;
  244. // A blocker will have been incremented when the task is created.
  245. // A writer we need to lock now.
  246. if (!token->is_blocker())
  247. token->add_writer(t);
  248. }
  249. // Iterate over the tokens.
  250. typedef Task_token** iterator;
  251. iterator
  252. begin()
  253. { return &this->tokens_[0]; }
  254. iterator
  255. end()
  256. { return &this->tokens_[this->count_]; }
  257. private:
  258. Task_locker(const Task_locker&);
  259. Task_locker& operator=(const Task_locker&);
  260. // The number of tokens.
  261. int count_;
  262. // The tokens.
  263. Task_token* tokens_[max_task_count];
  264. };
  265. } // End namespace gold.
  266. #endif // !defined(GOLD_TOKEN_H)