1 // token.h -- lock tokens for gold -*- C++ -*-
3 // Copyright 2006, 2007 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.
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
40 : head_(NULL
), tail_(NULL
)
44 { gold_assert(this->head_
== NULL
&& this->tail_
== NULL
); }
46 // Return whether the list is empty.
49 { return this->head_
== NULL
; }
51 // Add T to the end of the list.
55 // Remove the first Task on the list and return it. Return NULL if
61 // The start of the list. NULL if the list is empty.
63 // The end of the list. NULL if the list is empty.
67 // We support two basic types of locks, which are both implemented
68 // using the single class Task_token.
70 // A write lock may be held by a single Task at a time. This is used
71 // to control access to a single shared resource such as an Object.
73 // A blocker is used to indicate that a Task A must be run after some
74 // set of Tasks B. For each of the Tasks B, we increment the blocker
75 // when the Task is created, and decrement it when the Task is
76 // completed. When the count goes to 0, the task A is ready to run.
78 // There are no shared read locks. We always read and write objects
79 // in predictable patterns. The purpose of the locks is to permit
80 // some flexibility for the threading system, for cases where the
81 // execution order does not matter.
83 // These tokens are only manipulated when the workqueue lock is held
84 // or when they are first created. They do not require any locking
90 Task_token(bool is_blocker
)
91 : is_blocker_(is_blocker
), blockers_(0), writer_(NULL
), waiting_()
96 gold_assert(this->blockers_
== 0);
97 gold_assert(this->writer_
== NULL
);
100 // Return whether this is a blocker.
103 { return this->is_blocker_
; }
105 // A write lock token uses these methods.
107 // Is the token writable?
111 gold_assert(!this->is_blocker_
);
112 return this->writer_
== NULL
;
115 // Add the task as the token's writer (there may only be one
118 add_writer(const Task
* t
)
120 gold_assert(!this->is_blocker_
&& this->writer_
== NULL
);
124 // Remove the task as the token's writer.
126 remove_writer(const Task
* t
)
128 gold_assert(!this->is_blocker_
&& this->writer_
== t
);
129 this->writer_
= NULL
;
132 // A blocker token uses these methods.
134 // Add a blocker to the token.
138 gold_assert(this->is_blocker_
);
140 this->writer_
= NULL
;
143 // Remove a blocker from the token. Returns true if block count
148 gold_assert(this->is_blocker_
&& this->blockers_
> 0);
150 this->writer_
= NULL
;
151 return this->blockers_
== 0;
154 // Is the token currently blocked?
158 gold_assert(this->is_blocker_
);
159 return this->blockers_
> 0;
162 // Both blocker and write lock tokens use these methods.
164 // Add T to the list of tasks waiting for this token to be released.
167 { this->waiting_
.push_back(t
); }
169 // Remove the first Task waiting for this token to be released, and
170 // return it. Return NULL if no Tasks are waiting.
172 remove_first_waiting()
173 { return this->waiting_
.pop_front(); }
176 // It makes no sense to copy these.
177 Task_token(const Task_token
&);
178 Task_token
& operator=(const Task_token
&);
180 // Whether this is a blocker token.
182 // The number of blockers.
184 // The single writer.
186 // The list of Tasks waiting for this token to be released.
190 // In order to support tokens more reliably, we provide objects which
191 // handle them using RAII.
193 // RAII class to get a write lock on a token. This requires
194 // specifying the task which is doing the lock.
196 class Task_write_token
199 Task_write_token(Task_token
* token
, const Task
* task
)
200 : token_(token
), task_(task
)
201 { this->token_
->add_writer(this->task_
); }
204 { this->token_
->remove_writer(this->task_
); }
207 Task_write_token(const Task_write_token
&);
208 Task_write_token
& operator=(const Task_write_token
&);
214 // RAII class for a blocker.
216 class Task_block_token
219 // The blocker count must be incremented when the task is created.
220 // This object is created when the task is run, so we don't do
221 // anything in the constructor.
222 Task_block_token(Task_token
* token
)
224 { gold_assert(this->token_
->is_blocked()); }
227 { this->token_
->remove_blocker(); }
230 Task_block_token(const Task_block_token
&);
231 Task_block_token
& operator=(const Task_block_token
&);
236 // An object which implements an RAII lock for any object which
237 // supports lock and unlock methods.
239 template<typename Obj
>
243 Task_lock_obj(const Task
* task
, Obj
* obj
)
244 : task_(task
), obj_(obj
)
245 { this->obj_
->lock(task
); }
248 { this->obj_
->unlock(this->task_
); }
251 Task_lock_obj(const Task_lock_obj
&);
252 Task_lock_obj
& operator=(const Task_lock_obj
&);
258 // A class which holds the set of Task_tokens which must be locked for
259 // a Task. No Task requires more than four Task_tokens, so we set
265 static const int max_task_count
= 4;
277 { this->count_
= 0; }
279 // Add a token to the locker.
281 add(Task
* t
, Task_token
* token
)
283 gold_assert(this->count_
< max_task_count
);
284 this->tokens_
[this->count_
] = token
;
286 // A blocker will have been incremented when the task is created.
287 // A writer we need to lock now.
288 if (!token
->is_blocker())
289 token
->add_writer(t
);
292 // Iterate over the tokens.
294 typedef Task_token
** iterator
;
298 { return &this->tokens_
[0]; }
302 { return &this->tokens_
[this->count_
]; }
305 Task_locker(const Task_locker
&);
306 Task_locker
& operator=(const Task_locker
&);
308 // The number of tokens.
311 Task_token
* tokens_
[max_task_count
];
314 } // End namespace gold.
316 #endif // !defined(GOLD_TOKEN_H)