Changeset c64e254 in mainline


Ignore:
Timestamp:
2019-08-07T09:55:32Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
fcc4f86
Parents:
92a7cfb1
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-11-04 00:28:15)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-07 09:55:32)
Message:

sysman: Generalize closure creation to any graph ("visitor" pattern)

Location:
uspace/srv/sysman
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/sysman/job_closure.c

    r92a7cfb1 rc64e254  
    3838
    3939
     40/** Struct describes how to traverse units graph */
     41typedef struct {
     42        enum {
     43                BFS_FORWARD,  /**< Follow oriented edges */
     44                BFS_BACKWARD  /**< Go against oriented edges */
     45        } direction;
     46
     47        /** Visit a unit via edge
     48         * unit, incoming edge, user data
     49         * return result of visit (error stops further traversal)
     50         */
     51        int (* visit)(unit_t *, unit_edge_t *, void *);
     52
     53        /** Clean units remaining in BFS queue after error */
     54        void (* clean)(unit_t *, void *);
     55} bfs_ops_t;
     56
    4057/*
    4158 * Static functions
     
    6077}
    6178
    62 
    63 /*
    64  * Non-static functions
    65  */
    66 int job_create_closure(job_t *main_job, dyn_array_t *job_closure)
    67 {
    68         sysman_log(LVL_DEBUG2, "%s(%s)", __func__, unit_name(main_job->unit));
     79/** During visit creates job and appends it to closure
     80 *
     81 * @note Assumes BFS start unit's job is already present in closure!
     82 *
     83 * @return EOK on success
     84 */
     85static int start_visit(unit_t *u, unit_edge_t *e, void *arg)
     86{
     87        int rc = EOK;
     88        job_t *created_job = NULL;
     89        job_closure_t *closure = arg;
     90
     91        if (e == NULL) {
     92                assert(u->bfs_data == NULL);
     93                job_t *first_job = dyn_array_last(closure, job_t *);
     94
     95                job_add_ref(first_job);
     96                u->bfs_data = first_job;
     97
     98                goto finish;
     99        }
     100
     101        job_t *job = e->input->bfs_data;
     102        assert(job != NULL);
     103
     104        if (u->bfs_data == NULL) {
     105                created_job = job_create(u, job->target_state);
     106                if (created_job == NULL) {
     107                        rc = ENOMEM;
     108                        goto finish;
     109                }
     110
     111                /* Pass job reference to closure and add one for unit */
     112                rc = dyn_array_append(closure, job_t *, created_job);
     113                if (rc != EOK) {
     114                        goto finish;
     115                }
     116
     117                job_add_ref(created_job);
     118                u->bfs_data = created_job;
     119        }
     120
     121        /* Depending on edge type block existing jobs */
     122        rc = job_add_blocked_job(u->bfs_data, job);
     123
     124finish:
     125        if (rc != EOK) {
     126                job_del_ref(&created_job);
     127        }
     128        return rc;
     129}
     130
     131static void traverse_clean(unit_t *u, void *arg)
     132{
     133        job_t *job = u->bfs_data;
     134        job_del_ref(&job);
     135}
     136
     137static int bfs_traverse_component_internal(unit_t *origin, bfs_ops_t *ops,
     138    void *arg)
     139{
    69140        int rc;
    70141        list_t units_fifo;
    71142        list_initialize(&units_fifo);
    72143
    73         /* Check invariant */
    74         list_foreach(units, units, unit_t, u) {
    75                 assert(u->bfs_job == NULL);
    76         }
    77                
    78         unit_t *unit = main_job->unit;
    79         job_add_ref(main_job);
    80         unit->bfs_job = main_job;
     144        unit_t *unit = origin;
     145
     146        rc = ops->visit(unit, NULL, arg);
     147        if (rc != EOK) {
     148                goto finish;
     149        }
     150        unit->bfs_tag = true;
    81151        list_append(&unit->bfs_link, &units_fifo);
    82152       
     
    85155                    bfs_link);
    86156                list_remove(&unit->bfs_link);
    87                 job_t *job = unit->bfs_job;
    88                 assert(job != NULL);
    89 
    90                 job_add_ref(job);
    91                 dyn_array_append(job_closure, job_t *, job);
    92 
    93                 /*
    94                  * Traverse dependencies edges
    95                  * According to dependency type and edge direction create
    96                  * appropriate jobs (currently "After" only).
    97                  */
    98                 list_foreach(unit->edges_out, edges_out, unit_edge_t, e) {
     157
     158
     159                if (ops->direction == BFS_FORWARD)
     160                    list_foreach(unit->edges_out, edges_out, unit_edge_t, e) {
    99161                        unit_t *u = e->output;
    100                         job_t *blocking_job;
    101 
    102                         if (u->bfs_job == NULL) {
    103                                 blocking_job = job_create(u, job->target_state);
    104                                 if (blocking_job == NULL) {
    105                                         rc = ENOMEM;
    106                                         goto finish;
    107                                 }
    108                                 /* Pass reference to unit */
    109                                 u->bfs_job = blocking_job;
     162                        if (!u->bfs_tag) {
     163                                u->bfs_tag = true;
    110164                                list_append(&u->bfs_link, &units_fifo);
    111                         } else {
    112                                 blocking_job = u->bfs_job;
    113                         }
    114 
    115                         job_add_blocked_job(blocking_job, job);
    116                 }
    117         }
    118         sysman_log(LVL_DEBUG2, "%s(%s):", __func__, unit_name(main_job->unit));
    119         dyn_array_foreach(*job_closure, job_t *, job_it) {
    120                 sysman_log(LVL_DEBUG2, "%s\t%s, refs: %u", __func__,
    121                     unit_name((*job_it)->unit), atomic_get(&(*job_it)->refcnt));
     165                        }
     166                        rc = ops->visit(u, e, arg);
     167                        if (rc != EOK) {
     168                                goto finish;
     169                        }
     170                } else
     171                    list_foreach(unit->edges_in, edges_in, unit_edge_t, e) {
     172                        unit_t *u = e->input;
     173                        if (!u->bfs_tag) {
     174                                u->bfs_tag = true;
     175                                list_append(&u->bfs_link, &units_fifo);
     176                        }
     177                        rc = ops->visit(u, e, arg);
     178                        if (rc != EOK) {
     179                                goto finish;
     180                        }
     181                }
    122182        }
    123183        rc = EOK;
    124184
    125185finish:
    126         /* Unreference any jobs in interrupted BFS queue */
     186        /* Let user clean partially processed units */
    127187        list_foreach_safe(units_fifo, cur_link, next_link) {
    128188                unit_t *u = list_get_instance(cur_link, unit_t, bfs_link);
    129                 job_del_ref(&u->bfs_job);
     189                ops->clean(u, arg);
    130190                list_remove(cur_link);
    131191        }
     192       
     193        return rc;
     194}
     195
     196static int bfs_traverse_component(unit_t *origin, bfs_ops_t *ops, void *arg)
     197{
     198        /* Check invariant */
     199        list_foreach(units, units, unit_t, u) {
     200                assert(u->bfs_tag == false);
     201        }
     202        int rc = bfs_traverse_component_internal(origin, ops, arg);
     203
     204        /* Clean after ourselves (BFS tag jobs) */
     205        list_foreach(units, units, unit_t, u) {
     206                u->bfs_tag = false;
     207        }
     208        return rc;
     209}
     210
     211// TODO bfs_traverse_all
     212
     213
     214/*
     215 * Non-static functions
     216 */
     217
     218/** Creates job closure for given basic job
     219 *
     220 * @note It is caller's responsibility to clean job_closure (event on error).
     221 *
     222 * @return EOK on success otherwise propagated error
     223 */
     224int job_create_closure(job_t *main_job, job_closure_t *job_closure)
     225{
     226        sysman_log(LVL_DEBUG2, "%s(%s)", __func__, unit_name(main_job->unit));
     227
     228        static bfs_ops_t ops = {
     229                .direction = BFS_FORWARD,
     230                .visit = start_visit,
     231                .clean = traverse_clean,
     232        };
     233        int rc = dyn_array_append(job_closure, job_t *, main_job);
     234        if (rc != EOK) {
     235                return rc;
     236        }
     237        job_add_ref(main_job); /* Add one for the closure */
     238
     239        rc = bfs_traverse_component(main_job->unit, &ops, job_closure);
     240
     241        if (rc == EOK) {
     242                sysman_log(LVL_DEBUG2, "%s(%s):", __func__, unit_name(main_job->unit));
     243                dyn_array_foreach(*job_closure, job_t *, job_it) {
     244                        sysman_log(LVL_DEBUG2, "%s\t%s, refs: %u", __func__,
     245                            unit_name((*job_it)->unit), atomic_get(&(*job_it)->refcnt));
     246                }
     247        }
     248
    132249       
    133250        /* Clean after ourselves (BFS tag jobs) */
    134251        dyn_array_foreach(*job_closure, job_t *, job_it) {
    135                 assert(*job_it == (*job_it)->unit->bfs_job);
    136                 job_del_ref(&(*job_it)->unit->bfs_job);
    137                 (*job_it)->unit->bfs_job = NULL;
    138         }
    139 
    140         return rc;
    141 }
    142 
     252                job_t *j = (*job_it)->unit->bfs_data;
     253                assert(*job_it == j);
     254                job_del_ref(&j);
     255                (*job_it)->unit->bfs_data = NULL;
     256        }
     257
     258        return rc;
     259}
     260
  • uspace/srv/sysman/unit.h

    r92a7cfb1 rc64e254  
    6161        link_t bfs_link;
    6262
    63         /** Auxiliary job created during BFS traverse, its presence serves also
    64          * as BFS tag */
    65         job_t *bfs_job;
     63        /** Mark during BFS traversal unit is already queued */
     64        bool bfs_tag;
     65
     66        /** Auxiliary data for BFS traverse users .*/
     67        void *bfs_data;
    6668
    6769        /** Job assigned to unit in transitional state */
Note: See TracChangeset for help on using the changeset viewer.