~vojtech-horky/helenos/helenos-qemu

« back to all changes in this revision

Viewing changes to uspace/lib/c/generic/fibril.c

  • Committer: Jan Mares
  • Date: 2015-07-06 16:38:44 UTC
  • mfrom: (2103.1.249 HelenOS.mainline)
  • Revision ID: maresja1@gmail.com-20150706163844-big3j1vjinzit8j3
MergeĀ fromĀ mainline.

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
 
57
57
/**
58
58
 * This futex serializes access to ready_list,
59
 
 * serialized_list, manager_list and fibril_list.
 
59
 * manager_list and fibril_list.
60
60
 */
61
61
static futex_t fibril_futex = FUTEX_INITIALIZER;
62
62
 
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);
67
66
 
68
 
/** Number of threads that are executing a manager fibril. */
69
 
static int threads_in_manager;
70
 
 
71
 
/**
72
 
 * Number of threads that are executing a manager fibril
73
 
 * and are serialized. Protected by async_futex.
74
 
 */
75
 
static int serialized_threads;
76
 
 
77
 
/** Fibril-local count of serialization. If > 0, we must not preempt */
78
 
static fibril_local int serialization_count;
79
 
 
80
67
/** Function that spans the whole life-cycle of a fibril.
81
68
 *
82
69
 * Each fibril begins execution in this function. Then the function implementing
160
147
 */
161
148
int fibril_switch(fibril_switch_type_t stype)
162
149
{
163
 
        int retval = 0;
164
 
 
165
150
        if(stype == FIBRIL_DEFIBRILATE){
166
151
                futex_lock(&async_futex);
167
152
        }
168
153
        
169
154
        futex_lock(&fibril_futex);
170
 
        
171
 
        if (stype == FIBRIL_PREEMPT && list_empty(&ready_list))
172
 
                goto ret_0;
173
 
        
174
 
        if (stype == FIBRIL_FROM_MANAGER) {
175
 
                if ((list_empty(&ready_list)) && (list_empty(&serialized_list)))
176
 
                        goto ret_0;
177
 
                
178
 
                /*
179
 
                 * Do not preempt if there is not enough threads to run the
180
 
                 * ready fibrils which are not serialized.
181
 
                 */
182
 
                if ((list_empty(&serialized_list)) &&
183
 
                    (threads_in_manager <= serialized_threads)) {
184
 
                        goto ret_0;
 
155
 
 
156
        switch (stype) {
 
157
        case FIBRIL_PREEMPT:
 
158
        case FIBRIL_FROM_MANAGER:
 
159
                if (list_empty(&ready_list)) {
 
160
                        futex_unlock(&fibril_futex);
 
161
                        return 0;
185
162
                }
186
 
        }
187
 
        
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)) {
 
163
                break;
 
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);
192
169
 
 
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);
197
175
                }
 
176
                break;
198
177
        }
199
178
        
200
179
        fibril_t *srcf = __tcb_get()->fibril_data;
202
181
                
203
182
                /* Save current state */
204
183
                if (!context_save(&srcf->ctx)) {
205
 
                        if (serialization_count)
206
 
                                srcf->flags &= ~FIBRIL_SERIALIZED;
207
 
                        
208
184
                        if (srcf->clean_after_me) {
209
185
                                /*
210
186
                                 * Cleanup after the dead fibril from which we
229
205
                        return 1;       /* futex_unlock already done here */
230
206
                }
231
207
                
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 */
 
209
                switch (stype) {
 
210
                case FIBRIL_DEFIBRILATE:
 
211
                case FIBRIL_PREEMPT:
234
212
                        list_append(&srcf->link, &ready_list);
235
 
                else if (stype == FIBRIL_FROM_MANAGER) {
 
213
                        break;
 
214
                case FIBRIL_FROM_MANAGER:
236
215
                        list_append(&srcf->link, &manager_list);
237
 
                        threads_in_manager--;
238
 
                } else {
 
216
                        break;
 
217
                default:
 
218
                        assert(stype == FIBRIL_TO_MANAGER);
 
219
 
239
220
                        /*
240
 
                         * If stype == FIBRIL_TO_MANAGER, don't put ourselves to
241
 
                         * any list, we should already be somewhere, or we will
242
 
                         * be lost.
 
221
                         * Don't put the current fibril into any list, it should
 
222
                         * already be somewhere, or it will be lost.
243
223
                         */
 
224
                        break;
244
225
                }
245
226
        }
246
227
        
 
228
        fibril_t *dstf;
 
229
 
247
230
        /* Choose a new fibril to run */
248
 
        fibril_t *dstf;
249
 
        if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD) || (stype == FIBRIL_DEFIBRILATE)) {
 
231
        switch (stype) {
 
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,
251
236
                    link);
252
 
                if (serialization_count && stype == FIBRIL_TO_MANAGER) {
253
 
                        serialized_threads++;
254
 
                        srcf->flags |= FIBRIL_SERIALIZED;
 
237
 
 
238
                if(dstf == NULL){
 
239
                        assert(dstf!=NULL);
255
240
                }
256
 
                threads_in_manager++;
257
241
                
258
242
                if (stype == FIBRIL_FROM_DEAD) 
259
243
                        dstf->clean_after_me = srcf;
260
 
        } else {
261
 
                if (!list_empty(&serialized_list)) {
262
 
                        dstf = list_get_instance(list_first(&serialized_list),
263
 
                            fibril_t, link);
264
 
                        serialized_threads--;
265
 
                } else {
266
 
                        dstf = list_get_instance(list_first(&ready_list),
267
 
                            fibril_t, link);
268
 
                }
 
244
                break;
 
245
        default:
 
246
                dstf = list_get_instance(list_first(&ready_list), fibril_t,
 
247
                    link);
 
248
                break;
269
249
        }
 
250
 
270
251
        list_remove(&dstf->link);
271
252
        
272
253
        futex_unlock(&fibril_futex);
279
260
        
280
261
        context_restore(&dstf->ctx);
281
262
        /* not reached */
282
 
        
283
 
ret_0:
284
 
        futex_unlock(&fibril_futex);
285
 
        return retval;
286
263
}
287
264
 
288
265
/** Create a new fibril.
349
326
        fibril_t *fibril = (fibril_t *) fid;
350
327
        
351
328
        futex_lock(&fibril_futex);
352
 
        
353
 
        if ((fibril->flags & FIBRIL_SERIALIZED))
354
 
                list_append(&fibril->link, &serialized_list);
355
 
        else
356
 
                list_append(&fibril->link, &ready_list);
357
 
        
 
329
        list_append(&fibril->link, &ready_list);
358
330
        futex_unlock(&fibril_futex);
359
331
}
360
332
 
377
349
void fibril_remove_manager(void)
378
350
{
379
351
        futex_lock(&fibril_futex);
380
 
        
381
352
        if (!list_empty(&manager_list))
382
353
                list_remove(list_first(&manager_list));
383
 
        
384
354
        futex_unlock(&fibril_futex);
385
355
}
386
356
 
394
364
        return (fid_t) __tcb_get()->fibril_data;
395
365
}
396
366
 
397
 
/** Disable preemption
398
 
 *
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
403
 
 * futex as well.
404
 
 *
405
 
 */
406
 
void fibril_inc_sercount(void)
407
 
{
408
 
        serialization_count++;
409
 
}
410
 
 
411
 
/** Restore the preemption counter to the previous state. */
412
 
void fibril_dec_sercount(void)
413
 
{
414
 
        serialization_count--;
415
 
}
416
 
 
417
 
int fibril_get_sercount(void)
418
 
{
419
 
        return serialization_count;
420
 
}
421
 
 
422
367
/** @}
423
368
 */