Changeset 04803bf in mainline for uspace/lib/c/generic/fibril.c


Ignore:
Timestamp:
2011-03-21T22:00:17Z (15 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
143932e3
Parents:
b50b5af2 (diff), 7308e84 (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 (needs fixes).

File:
1 moved

Legend:

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

    rb50b5af2 r04803bf  
    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        fibril->waits_for = NULL;
     119       
     120        return fibril;
     121}
     122
     123void fibril_teardown(fibril_t *fibril)
     124{
     125        __free_tls(fibril->tcb);
     126        free(fibril);
    120127}
    121128
     
    125132 * held.
    126133 *
    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.
     134 * @param stype Switch type. One of FIBRIL_PREEMPT, FIBRIL_TO_MANAGER,
     135 *              FIBRIL_FROM_MANAGER, FIBRIL_FROM_DEAD. The parameter
     136 *              describes the circumstances of the switch.
     137 *
     138 * @return 0 if there is no ready fibril,
     139 * @return 1 otherwise.
     140 *
    132141 */
    133142int fibril_switch(fibril_switch_type_t stype)
    134143{
    135         fibril_t *srcf, *dstf;
    136144        int retval = 0;
    137145       
    138146        futex_down(&fibril_futex);
    139 
     147       
    140148        if (stype == FIBRIL_PREEMPT && list_empty(&ready_list))
    141149                goto ret_0;
    142 
     150       
    143151        if (stype == FIBRIL_FROM_MANAGER) {
    144                 if (list_empty(&ready_list) && list_empty(&serialized_list))
     152                if ((list_empty(&ready_list)) && (list_empty(&serialized_list)))
    145153                        goto ret_0;
     154               
    146155                /*
    147156                 * Do not preempt if there is not enough threads to run the
    148157                 * ready fibrils which are not serialized.
    149158                 */
    150                 if (list_empty(&serialized_list) &&
    151                     threads_in_manager <= serialized_threads) {
     159                if ((list_empty(&serialized_list)) &&
     160                    (threads_in_manager <= serialized_threads)) {
    152161                        goto ret_0;
    153162                }
    154163        }
     164       
    155165        /* If we are going to manager and none exists, create it */
    156         if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) {
     166        if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
    157167                while (list_empty(&manager_list)) {
    158168                        futex_up(&fibril_futex);
     
    162172        }
    163173       
    164         srcf = __tcb_get()->fibril_data;
     174        fibril_t *srcf = __tcb_get()->fibril_data;
    165175        if (stype != FIBRIL_FROM_DEAD) {
     176               
    166177                /* Save current state */
    167178                if (!context_save(&srcf->ctx)) {
    168179                        if (serialization_count)
    169180                                srcf->flags &= ~FIBRIL_SERIALIZED;
     181                       
    170182                        if (srcf->clean_after_me) {
    171183                                /*
     
    173185                                 * restored context here.
    174186                                 */
    175                                 void *stack = srcf->clean_after_me->stack; 
     187                                void *stack = srcf->clean_after_me->stack;
    176188                                if (stack) {
    177189                                        /*
     
    188200                                srcf->clean_after_me = NULL;
    189201                        }
     202                       
    190203                        return 1;       /* futex_up already done here */
    191204                }
    192 
     205               
    193206                /* Save myself to the correct run list */
    194207                if (stype == FIBRIL_PREEMPT)
     
    197210                        list_append(&srcf->link, &manager_list);
    198211                        threads_in_manager--;
    199                 } else {       
     212                } else {
    200213                        /*
    201214                         * If stype == FIBRIL_TO_MANAGER, don't put ourselves to
     
    207220       
    208221        /* Choose a new fibril to run */
    209         if (stype == FIBRIL_TO_MANAGER || stype == FIBRIL_FROM_DEAD) {
     222        fibril_t *dstf;
     223        if ((stype == FIBRIL_TO_MANAGER) || (stype == FIBRIL_FROM_DEAD)) {
    210224                dstf = list_get_instance(manager_list.next, fibril_t, link);
    211225                if (serialization_count && stype == FIBRIL_TO_MANAGER) {
     
    214228                }
    215229                threads_in_manager++;
    216 
     230               
    217231                if (stype == FIBRIL_FROM_DEAD)
    218232                        dstf->clean_after_me = srcf;
     
    228242        }
    229243        list_remove(&dstf->link);
    230 
     244       
    231245        futex_up(&fibril_futex);
    232246        context_restore(&dstf->ctx);
    233247        /* not reached */
    234 
     248       
    235249ret_0:
    236250        futex_up(&fibril_futex);
     
    240254/** Create a new fibril.
    241255 *
    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.
     256 * @param func Implementing function of the new fibril.
     257 * @param arg Argument to pass to func.
     258 *
     259 * @return 0 on failure or TLS of the new fibril.
     260 *
    246261 */
    247262fid_t fibril_create(int (*func)(void *), void *arg)
    248263{
    249         fibril_t *f;
    250 
    251         f = fibril_setup();
    252         if (!f)
     264        fibril_t *fibril;
     265       
     266        fibril = fibril_setup();
     267        if (fibril == NULL)
    253268                return 0;
    254         f->stack = (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO *
    255             getpagesize());
    256         if (!f->stack) {
    257                 fibril_teardown(f);
     269       
     270        fibril->stack =
     271            (char *) malloc(FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize());
     272        if (!fibril->stack) {
     273                fibril_teardown(fibril);
    258274                return 0;
    259275        }
    260276       
    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;
     277        fibril->func = func;
     278        fibril->arg = arg;
     279
     280        context_save(&fibril->ctx);
     281        context_set(&fibril->ctx, FADDR(fibril_main), fibril->stack,
     282            FIBRIL_INITIAL_STACK_PAGES_NO * getpagesize(), fibril->tcb);
     283
     284        return (fid_t) fibril;
    269285}
    270286
    271287/** Add a fibril to the ready list.
    272288 *
    273  * @param fid           Pointer to the fibril structure of the fibril to be
    274  *                      added.
     289 * @param fid Pointer to the fibril structure of the fibril to be
     290 *            added.
     291 *
    275292 */
    276293void fibril_add_ready(fid_t fid)
    277294{
    278         fibril_t *f;
    279 
    280         f = (fibril_t *) fid;
     295        fibril_t *fibril = (fibril_t *) fid;
     296       
    281297        futex_down(&fibril_futex);
    282         if ((f->flags & FIBRIL_SERIALIZED))
    283                 list_append(&f->link, &serialized_list);
     298       
     299        if ((fibril->flags & FIBRIL_SERIALIZED))
     300                list_append(&fibril->link, &serialized_list);
    284301        else
    285                 list_append(&f->link, &ready_list);
     302                list_append(&fibril->link, &ready_list);
     303       
    286304        futex_up(&fibril_futex);
    287305}
     
    289307/** Add a fibril to the manager list.
    290308 *
    291  * @param fid           Pointer to the fibril structure of the fibril to be
    292  *                      added.
     309 * @param fid Pointer to the fibril structure of the fibril to be
     310 *            added.
     311 *
    293312 */
    294313void fibril_add_manager(fid_t fid)
    295314{
    296         fibril_t *f;
    297 
    298         f = (fibril_t *) fid;
    299 
     315        fibril_t *fibril = (fibril_t *) fid;
     316       
    300317        futex_down(&fibril_futex);
    301         list_append(&f->link, &manager_list);
     318        list_append(&fibril->link, &manager_list);
    302319        futex_up(&fibril_futex);
    303320}
     
    307324{
    308325        futex_down(&fibril_futex);
    309         if (list_empty(&manager_list)) {
    310                 futex_up(&fibril_futex);
    311                 return;
    312         }
    313         list_remove(manager_list.next);
     326       
     327        if (!list_empty(&manager_list))
     328                list_remove(manager_list.next);
     329       
    314330        futex_up(&fibril_futex);
    315331}
     
    345361}
    346362
     363int fibril_get_sercount(void)
     364{
     365        return serialization_count;
     366}
     367
    347368/** @}
    348369 */
Note: See TracChangeset for help on using the changeset viewer.