2011-03-24 Eric B. Weddington <eric.weddington@atmel.com>
[binutils.git] / gold / token.h
blob5cf64a0d402640575ee1c5fb13360b34bd54e166
1 // token.h -- lock tokens for gold -*- C++ -*-
3 // Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
4 // Written by Ian Lance Taylor <iant@google.com>.
6 // This file is part of gold.
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21 // MA 02110-1301, USA.
23 #ifndef GOLD_TOKEN_H
24 #define GOLD_TOKEN_H
26 namespace gold
29 class Condvar;
30 class Task;
32 // A list of Tasks, managed through the next_locked_ field in the
33 // class Task. We define this class here because we need it in
34 // Task_token.
36 class Task_list
38 public:
39 Task_list()
40 : head_(NULL), tail_(NULL)
41 { }
43 ~Task_list()
44 { gold_assert(this->head_ == NULL && this->tail_ == NULL); }
46 // Return whether the list is empty.
47 bool
48 empty() const
49 { return this->head_ == NULL; }
51 // Add T to the head of the list.
52 void
53 push_front(Task* t);
55 // Add T to the end of the list.
56 void
57 push_back(Task* t);
59 // Remove the first Task on the list and return it. Return NULL if
60 // the list is empty.
61 Task*
62 pop_front();
64 private:
65 // The start of the list. NULL if the list is empty.
66 Task* head_;
67 // The end of the list. NULL if the list is empty.
68 Task* tail_;
71 // We support two basic types of locks, which are both implemented
72 // using the single class Task_token.
74 // A write lock may be held by a single Task at a time. This is used
75 // to control access to a single shared resource such as an Object.
77 // A blocker is used to indicate that a Task A must be run after some
78 // set of Tasks B. For each of the Tasks B, we increment the blocker
79 // when the Task is created, and decrement it when the Task is
80 // completed. When the count goes to 0, the task A is ready to run.
82 // There are no shared read locks. We always read and write objects
83 // in predictable patterns. The purpose of the locks is to permit
84 // some flexibility for the threading system, for cases where the
85 // execution order does not matter.
87 // These tokens are only manipulated when the workqueue lock is held
88 // or when they are first created. They do not require any locking
89 // themselves.
91 class Task_token
93 public:
94 Task_token(bool is_blocker)
95 : is_blocker_(is_blocker), blockers_(0), writer_(NULL), waiting_()
96 { }
98 ~Task_token()
100 gold_assert(this->blockers_ == 0);
101 gold_assert(this->writer_ == NULL);
104 // Return whether this is a blocker.
105 bool
106 is_blocker() const
107 { return this->is_blocker_; }
109 // A write lock token uses these methods.
111 // Is the token writable?
112 bool
113 is_writable() const
115 gold_assert(!this->is_blocker_);
116 return this->writer_ == NULL;
119 // Add the task as the token's writer (there may only be one
120 // writer).
121 void
122 add_writer(const Task* t)
124 gold_assert(!this->is_blocker_ && this->writer_ == NULL);
125 this->writer_ = t;
128 // Remove the task as the token's writer.
129 void
130 remove_writer(const Task* t)
132 gold_assert(!this->is_blocker_ && this->writer_ == t);
133 this->writer_ = NULL;
136 // A blocker token uses these methods.
138 // Add a blocker to the token.
139 void
140 add_blocker()
142 gold_assert(this->is_blocker_);
143 ++this->blockers_;
144 this->writer_ = NULL;
147 // Add some number of blockers to the token.
148 void
149 add_blockers(int c)
151 gold_assert(this->is_blocker_);
152 this->blockers_ += c;
153 this->writer_ = NULL;
156 // Remove a blocker from the token. Returns true if block count
157 // drops to zero.
158 bool
159 remove_blocker()
161 gold_assert(this->is_blocker_ && this->blockers_ > 0);
162 --this->blockers_;
163 this->writer_ = NULL;
164 return this->blockers_ == 0;
167 // Is the token currently blocked?
168 bool
169 is_blocked() const
171 gold_assert(this->is_blocker_);
172 return this->blockers_ > 0;
175 // Both blocker and write lock tokens use these methods.
177 // Add T to the list of tasks waiting for this token to be released.
178 void
179 add_waiting(Task* t)
180 { this->waiting_.push_back(t); }
182 // Add T to the front of the list of tasks waiting for this token to
183 // be released.
184 void
185 add_waiting_front(Task* t)
186 { this->waiting_.push_front(t); }
188 // Remove the first Task waiting for this token to be released, and
189 // return it. Return NULL if no Tasks are waiting.
190 Task*
191 remove_first_waiting()
192 { return this->waiting_.pop_front(); }
194 private:
195 // It makes no sense to copy these.
196 Task_token(const Task_token&);
197 Task_token& operator=(const Task_token&);
199 // Whether this is a blocker token.
200 bool is_blocker_;
201 // The number of blockers.
202 int blockers_;
203 // The single writer.
204 const Task* writer_;
205 // The list of Tasks waiting for this token to be released.
206 Task_list waiting_;
209 // In order to support tokens more reliably, we provide objects which
210 // handle them using RAII.
212 // RAII class to get a write lock on a token. This requires
213 // specifying the task which is doing the lock.
215 class Task_write_token
217 public:
218 Task_write_token(Task_token* token, const Task* task)
219 : token_(token), task_(task)
220 { this->token_->add_writer(this->task_); }
222 ~Task_write_token()
223 { this->token_->remove_writer(this->task_); }
225 private:
226 Task_write_token(const Task_write_token&);
227 Task_write_token& operator=(const Task_write_token&);
229 Task_token* token_;
230 const Task* task_;
233 // RAII class for a blocker.
235 class Task_block_token
237 public:
238 // The blocker count must be incremented when the task is created.
239 // This object is created when the task is run, so we don't do
240 // anything in the constructor.
241 Task_block_token(Task_token* token)
242 : token_(token)
243 { gold_assert(this->token_->is_blocked()); }
245 ~Task_block_token()
246 { this->token_->remove_blocker(); }
248 private:
249 Task_block_token(const Task_block_token&);
250 Task_block_token& operator=(const Task_block_token&);
252 Task_token* token_;
255 // An object which implements an RAII lock for any object which
256 // supports lock and unlock methods.
258 template<typename Obj>
259 class Task_lock_obj
261 public:
262 Task_lock_obj(const Task* task, Obj* obj)
263 : task_(task), obj_(obj)
264 { this->obj_->lock(task); }
266 ~Task_lock_obj()
267 { this->obj_->unlock(this->task_); }
269 private:
270 Task_lock_obj(const Task_lock_obj&);
271 Task_lock_obj& operator=(const Task_lock_obj&);
273 const Task* task_;
274 Obj* obj_;
277 // A class which holds the set of Task_tokens which must be locked for
278 // a Task. No Task requires more than four Task_tokens, so we set
279 // that as a limit.
281 class Task_locker
283 public:
284 static const int max_task_count = 4;
286 Task_locker()
287 : count_(0)
290 ~Task_locker()
293 // Clear the locker.
294 void
295 clear()
296 { this->count_ = 0; }
298 // Add a token to the locker.
299 void
300 add(Task* t, Task_token* token)
302 gold_assert(this->count_ < max_task_count);
303 this->tokens_[this->count_] = token;
304 ++this->count_;
305 // A blocker will have been incremented when the task is created.
306 // A writer we need to lock now.
307 if (!token->is_blocker())
308 token->add_writer(t);
311 // Iterate over the tokens.
313 typedef Task_token** iterator;
315 iterator
316 begin()
317 { return &this->tokens_[0]; }
319 iterator
320 end()
321 { return &this->tokens_[this->count_]; }
323 private:
324 Task_locker(const Task_locker&);
325 Task_locker& operator=(const Task_locker&);
327 // The number of tokens.
328 int count_;
329 // The tokens.
330 Task_token* tokens_[max_task_count];
333 } // End namespace gold.
335 #endif // !defined(GOLD_TOKEN_H)