58
58
* This futex serializes access to ready_list,
59
* serialized_list, manager_list and fibril_list.
59
* manager_list and fibril_list.
61
61
static futex_t fibril_futex = FUTEX_INITIALIZER;
63
63
static LIST_INITIALIZE(ready_list);
64
static LIST_INITIALIZE(serialized_list);
65
64
static LIST_INITIALIZE(manager_list);
66
65
static LIST_INITIALIZE(fibril_list);
68
/** Number of threads that are executing a manager fibril. */
69
static int threads_in_manager;
72
* Number of threads that are executing a manager fibril
73
* and are serialized. Protected by async_futex.
75
static int serialized_threads;
77
/** Fibril-local count of serialization. If > 0, we must not preempt */
78
static fibril_local int serialization_count;
80
67
/** Function that spans the whole life-cycle of a fibril.
82
69
* Each fibril begins execution in this function. Then the function implementing
161
148
int fibril_switch(fibril_switch_type_t stype)
165
150
if(stype == FIBRIL_DEFIBRILATE){
166
151
futex_lock(&async_futex);
169
154
futex_lock(&fibril_futex);
171
if (stype == FIBRIL_PREEMPT && list_empty(&ready_list))
174
if (stype == FIBRIL_FROM_MANAGER) {
175
if ((list_empty(&ready_list)) && (list_empty(&serialized_list)))
179
* Do not preempt if there is not enough threads to run the
180
* ready fibrils which are not serialized.
182
if ((list_empty(&serialized_list)) &&
183
(threads_in_manager <= serialized_threads)) {
158
case FIBRIL_FROM_MANAGER:
159
if (list_empty(&ready_list)) {
160
futex_unlock(&fibril_futex);
188
/* If we are going to manager and none exists, create it */
189
if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD) || (stype == FIBRIL_DEFIBRILATE)) {
164
case FIBRIL_TO_MANAGER:
165
case FIBRIL_FROM_DEAD:
166
case FIBRIL_DEFIBRILATE:
190
167
/* Make sure the async_futex is held. */
191
168
assert((atomic_signed_t) async_futex.val.count <= 0);
170
/* If we are going to manager and none exists, create it */
193
171
while (list_empty(&manager_list)) {
194
172
futex_unlock(&fibril_futex);
195
173
async_create_manager();
196
174
futex_lock(&fibril_futex);
200
179
fibril_t *srcf = __tcb_get()->fibril_data;
229
205
return 1; /* futex_unlock already done here */
232
/* Save myself to the correct run list */
233
if ((stype == FIBRIL_PREEMPT) || (stype == FIBRIL_DEFIBRILATE))
208
/* Put the current fibril into the correct run list */
210
case FIBRIL_DEFIBRILATE:
234
212
list_append(&srcf->link, &ready_list);
235
else if (stype == FIBRIL_FROM_MANAGER) {
214
case FIBRIL_FROM_MANAGER:
236
215
list_append(&srcf->link, &manager_list);
237
threads_in_manager--;
218
assert(stype == FIBRIL_TO_MANAGER);
240
* If stype == FIBRIL_TO_MANAGER, don't put ourselves to
241
* any list, we should already be somewhere, or we will
221
* Don't put the current fibril into any list, it should
222
* already be somewhere, or it will be lost.
247
230
/* Choose a new fibril to run */
249
if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD) || (stype == FIBRIL_DEFIBRILATE)) {
232
case FIBRIL_TO_MANAGER:
233
case FIBRIL_FROM_DEAD:
234
case FIBRIL_DEFIBRILATE:
250
235
dstf = list_get_instance(list_first(&manager_list), fibril_t,
252
if (serialization_count && stype == FIBRIL_TO_MANAGER) {
253
serialized_threads++;
254
srcf->flags |= FIBRIL_SERIALIZED;
256
threads_in_manager++;
258
242
if (stype == FIBRIL_FROM_DEAD)
259
243
dstf->clean_after_me = srcf;
261
if (!list_empty(&serialized_list)) {
262
dstf = list_get_instance(list_first(&serialized_list),
264
serialized_threads--;
266
dstf = list_get_instance(list_first(&ready_list),
246
dstf = list_get_instance(list_first(&ready_list), fibril_t,
270
251
list_remove(&dstf->link);
272
253
futex_unlock(&fibril_futex);
349
326
fibril_t *fibril = (fibril_t *) fid;
351
328
futex_lock(&fibril_futex);
353
if ((fibril->flags & FIBRIL_SERIALIZED))
354
list_append(&fibril->link, &serialized_list);
356
list_append(&fibril->link, &ready_list);
329
list_append(&fibril->link, &ready_list);
358
330
futex_unlock(&fibril_futex);
377
349
void fibril_remove_manager(void)
379
351
futex_lock(&fibril_futex);
381
352
if (!list_empty(&manager_list))
382
353
list_remove(list_first(&manager_list));
384
354
futex_unlock(&fibril_futex);
394
364
return (fid_t) __tcb_get()->fibril_data;
397
/** Disable preemption
399
* If the fibril wants to send several message in a row and does not want to be
400
* preempted, it should start async_serialize_start() in the beginning of
401
* communication and async_serialize_end() in the end. If it is a true
402
* multithreaded application, it should protect the communication channel by a
406
void fibril_inc_sercount(void)
408
serialization_count++;
411
/** Restore the preemption counter to the previous state. */
412
void fibril_dec_sercount(void)
414
serialization_count--;
417
int fibril_get_sercount(void)
419
return serialization_count;