Changeset c47e1a8 in mainline for uspace/lib/c/generic/fibril.c


Ignore:
Timestamp:
2010-05-21T07:50:04Z (16 years ago)
Author:
Lenka Trochtova <trochtova.lenka@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d51ee2b
Parents:
cf8cc36 (diff), 15b592b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

merge mainline changes (rev. 451)

File:
1 moved

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/fibril.c

    rcf8cc36 rc47e1a8  
    4141#include <unistd.h>
    4242#include <stdio.h>
     43#include <arch/barrier.h>
    4344#include <libarch/faddr.h>
    4445#include <futex.h>
     
    4748
    4849#ifndef FIBRIL_INITIAL_STACK_PAGES_NO
    49 #define FIBRIL_INITIAL_STACK_PAGES_NO   1
     50        #define FIBRIL_INITIAL_STACK_PAGES_NO  1
    5051#endif
    5152
    5253/**
    53  * This futex serializes access to ready_list, serialized_list and manager_list.
    54  */
     54 * This futex serializes access to ready_list,
     55 * serialized_list and manager_list.
     56 */
    5557static atomic_t fibril_futex = FUTEX_INITIALIZER;
    5658
     
    5961static LIST_INITIALIZE(manager_list);
    6062
    61 static void fibril_main(void);
    62 
    6363/** Number of threads that are executing a manager fibril. */
    6464static int threads_in_manager;
    65 /** Number of threads that are executing a manager fibril and are serialized. */
    66 static int serialized_threads;  /* Protected by async_futex */
     65
     66/**
     67 * Number of threads that are executing a manager fibril
     68 * and are serialized. Protected by async_futex.
     69 */
     70static int serialized_threads;
     71
    6772/** Fibril-local count of serialization. If > 0, we must not preempt */
    6873static fibril_local int serialization_count;
    69 
    70 /** Setup fibril information into TCB structure */
    71 fibril_t *fibril_setup(void)
    72 {
    73         fibril_t *f;
    74         tcb_t *tcb;
    75 
    76         tcb = __make_tls();
    77         if (!tcb)
    78                 return NULL;
    79 
    80         f = malloc(sizeof(fibril_t));
    81         if (!f) {
    82                 __free_tls(tcb);
    83                 return NULL;
    84         }
    85 
    86         tcb->fibril_data = f;
    87         f->tcb = tcb;
    88 
    89         f->func = NULL;
    90         f->arg = NULL;
    91         f->stack = NULL;
    92         f->clean_after_me = NULL;
    93         f->retval = 0;
    94         f->flags = 0;
    95 
    96         return f;
    97 }
    98 
    99 void fibril_teardown(fibril_t *f)
    100 {
    101         __free_tls(f->tcb);
    102         free(f);
    103 }
    10474
    10575/** Function that spans the whole life-cycle of a fibril.
     
    10878 * the fibril logic is called.  After its return, the return value is saved.
    10979 * The fibril then switches to another fibril, which cleans up after it.
    110  */
    111 void fibril_main(void)
    112 {
    113         fibril_t *f = __tcb_get()->fibril_data;
    114 
     80 *
     81 */
     82static void fibril_main(void)
     83{
     84        fibril_t *fibril = __tcb_get()->fibril_data;
     85       
    11586        /* Call the implementing function. */
    116         f->retval = f->func(f->arg);
    117 
     87        fibril->retval = fibril->func(fibril->arg);
     88       
    11889        fibril_switch(FIBRIL_FROM_DEAD);
    119         /* not reached */
     90        /* Not reached */
     91}
     92
     93/** Setup fibril information into TCB structure
     94 *
     95 */
     96fibril_t *fibril_setup(void)
     97{
     98        tcb_t *tcb = __make_tls();
     99        if (!tcb)
     100                return NULL;
     101       
     102        fibril_t *fibril = malloc(sizeof(fibril_t));
     103        if (!fibril) {
     104                __free_tls(tcb);
     105                return NULL;
     106        }
     107       
     108        tcb->fibril_data = fibril;
     109        fibril->tcb = tcb;
     110       
     111        fibril->func = NULL;
     112        fibril->arg = NULL;
     113        fibril->stack = NULL;
     114        fibril->clean_after_me = NULL;
     115        fibril->retval = 0;
     116        fibril->flags = 0;
     117       
     118        return fibril;
     119}
     120
     121void fibril_teardown(fibril_t *fibril)
     122{
     123        __free_tls(fibril->tcb);
     124        free(fibril);
    120125}
    121126
     
    125130 * held.
    126131 *
    127  * @param stype         Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
    128  *                      FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter
    129  *                      describes the circumstances of the switch.
    130  * @return              Return 0 if there is no ready fibril,
    131  *                      return 1 otherwise.
     132 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     133 *              FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter
     134 *              describes the circumstances of the switch.
     135 *
     136 * @return 0 if there is no ready fibril,
     137 * @return 1 otherwise.
     138 *
    132139 */
    133140int fibril_switch(fibril_switch_type_t stype)
    134141{
    135         fibril_t *srcf, *dstf;
    136142        int retval = 0;
    137143       
    138144        futex_down(&fibril_futex);
    139 
     145       
    140146        if (stype == FIBRIL_PREEMPT && list_empty(&ready_list))
    141147                goto ret_0;
    142 
     148       
    143149        if (stype == FIBRIL_FROM_MANAGER) {
    144                 if (list_empty(&ready_list) && list_empty(&serialized_list))
     150                if ((list_empty(&ready_list)) && (list_empty(&serialized_list)))
    145151                        goto ret_0;
     152               
    146153                /*
    147154                 * Do not preempt if there is not enough threads to run the
    148155                 * ready fibrils which are not serialized.
    149156                 */
    150                 if (list_empty(&serialized_list) &&
    151                     threads_in_manager <= serialized_threads) {
     157                if ((list_empty(&serialized_list)) &&
     158                    (threads_in_manager <= serialized_threads)) {
    152159                        goto ret_0;
    153160                }
    154161        }
     162       
    155163        /* If we are going to manager and none exists, create it */
    156         if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) {
     164        if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
    157165                while (list_empty(&manager_list)) {
    158166                        futex_up(&fibril_futex);
     
    162170        }
    163171       
    164         srcf = __tcb_get()->fibril_data;
     172        fibril_t *srcf = __tcb_get()->fibril_data;
    165173        if (stype != FIBRIL_FROM_DEAD) {
     174               
    166175                /* Save current state */
    167176                if (!context_save(&srcf->ctx)) {
    168177                        if (serialization_count)
    169178                                srcf->flags &= ~FIBRIL_SERIALIZED;
     179                       
    170180                        if (srcf->clean_after_me) {
    171181                                /*
     
    173183                                 * restored context here.
    174184                                 */
    175                                 void *stack = srcf->clean_after_me->stack; 
     185                                void *stack = srcf->clean_after_me->stack;
    176186                                if (stack) {
    177187                                        /*
     
    188198                                srcf->clean_after_me = NULL;
    189199                        }
     200                       
    190201                        return 1;       /* futex_up already done here */
    191202                }
    192 
     203               
    193204                /* Save myself to the correct run list */
    194205                if (stype == FIBRIL_PREEMPT)
     
    197208                        list_append(&srcf->link, &manager_list);
    198209                        threads_in_manager--;
    199                 } else {       
     210                } else {
    200211                        /*
    201212                         * If stype == FIBRIL_TO_MANAGER, don't put ourselves to
     
    207218       
    208219        /* Choose a new fibril to run */
    209         if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) {
     220        fibril_t *dstf;
     221        if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
    210222                dstf = list_get_instance(manager_list.next, fibril_t, link);
    211223                if (serialization_count && stype == FIBRIL_TO_MANAGER) {
     
    214226                }
    215227                threads_in_manager++;
    216 
     228               
    217229                if (stype == FIBRIL_FROM_DEAD)
    218230                        dstf->clean_after_me = srcf;
     
    228240        }
    229241        list_remove(&dstf->link);
    230 
     242       
    231243        futex_up(&fibril_futex);
    232244        context_restore(&dstf->ctx);
    233245        /* not reached */
    234 
     246       
    235247ret_0:
    236248        futex_up(&fibril_futex);
     
    240252/** Create a new fibril.
    241253 *
    242  * @param func          Implementing function of the new fibril.
    243  * @param arg           Argument to pass to func.
    244  *
    245  * @return              Return 0 on failure or TLS of the new fibril.
     254 * @param func Implementing function of the new fibril.
     255 * @param arg Argument to pass to func.
     256 *
     257 * @return 0 on failure or TLS of the new fibril.
     258 *
    246259 */
    247260fid_t fibril_create(int (*func)(void *), void *arg)
    248261{
    249         fibril_t *f;
    250 
    251         f = fibril_setup();
    252         if (!f)
     262        fibril_t *fibril;
     263       
     264        fibril = fibril_setup();
     265        if (fibril == NULL)
    253266                return 0;
    254         f->stack = (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO *
    255             getpagesize());
    256         if (!f->stack) {
    257                 fibril_teardown(f);
     267       
     268        fibril->stack =
     269            (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize());
     270        if (!fibril->stack) {
     271                fibril_teardown(fibril);
    258272                return 0;
    259273        }
    260274       
    261         f->func = func;
    262         f->arg = arg;
    263 
    264         context_save(&f->ctx);
    265         context_set(&f->ctx, FADDR(fibril_main), f->stack,
    266             FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), f->tcb);
    267 
    268         return (fid_t) f;
     275        fibril->func = func;
     276        fibril->arg = arg;
     277       
     278        context_save(&fibril->ctx);
     279        context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack,
     280            FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), fibril->tcb);
     281
     282        return (fid_t) fibril;
    269283}
    270284
    271285/** Add a fibril to the ready list.
    272286 *
    273  * @param fid           Pointer to the fibril structure of the fibril to be
    274  *                      added.
     287 * @param fid Pointer to the fibril structure of the fibril to be
     288 *            added.
     289 *
    275290 */
    276291void fibril_add_ready(fid_t fid)
    277292{
    278         fibril_t *f;
    279 
    280         f = (fibril_t *) fid;
     293        fibril_t *fibril = (fibril_t *) fid;
     294       
    281295        futex_down(&fibril_futex);
    282         if ((f->flags & FIBRIL_SERIALIZED))
    283                 list_append(&f->link, &serialized_list);
     296       
     297        if ((fibril->flags & FIBRIL_SERIALIZED))
     298                list_append(&fibril->link, &serialized_list);
    284299        else
    285                 list_append(&f->link, &ready_list);
     300                list_append(&fibril->link, &ready_list);
     301       
    286302        futex_up(&fibril_futex);
    287303}
     
    289305/** Add a fibril to the manager list.
    290306 *
    291  * @param fid           Pointer to the fibril structure of the fibril to be
    292  *                      added.
     307 * @param fid Pointer to the fibril structure of the fibril to be
     308 *            added.
     309 *
    293310 */
    294311void fibril_add_manager(fid_t fid)
    295312{
    296         fibril_t *f;
    297 
    298         f = (fibril_t *) fid;
    299 
     313        fibril_t *fibril = (fibril_t *) fid;
     314       
    300315        futex_down(&fibril_futex);
    301         list_append(&f->link, &manager_list);
     316        list_append(&fibril->link, &manager_list);
    302317        futex_up(&fibril_futex);
    303318}
     
    307322{
    308323        futex_down(&fibril_futex);
    309         if (list_empty(&manager_list)) {
    310                 futex_up(&fibril_futex);
    311                 return;
    312         }
    313         list_remove(manager_list.next);
     324       
     325        if (!list_empty(&manager_list))
     326                list_remove(manager_list.next);
     327       
    314328        futex_up(&fibril_futex);
    315329}
Note: See TracChangeset for help on using the changeset viewer.