Changeset c64e254 in mainline
- Timestamp:
- 2019-08-07T09:55:32Z (5 years ago)
- 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)
- Location:
- uspace/srv/sysman
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/sysman/job_closure.c
r92a7cfb1 rc64e254 38 38 39 39 40 /** Struct describes how to traverse units graph */ 41 typedef 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 40 57 /* 41 58 * Static functions … … 60 77 } 61 78 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 */ 85 static 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 124 finish: 125 if (rc != EOK) { 126 job_del_ref(&created_job); 127 } 128 return rc; 129 } 130 131 static void traverse_clean(unit_t *u, void *arg) 132 { 133 job_t *job = u->bfs_data; 134 job_del_ref(&job); 135 } 136 137 static int bfs_traverse_component_internal(unit_t *origin, bfs_ops_t *ops, 138 void *arg) 139 { 69 140 int rc; 70 141 list_t units_fifo; 71 142 list_initialize(&units_fifo); 72 143 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; 81 151 list_append(&unit->bfs_link, &units_fifo); 82 152 … … 85 155 bfs_link); 86 156 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) { 99 161 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; 110 164 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 } 122 182 } 123 183 rc = EOK; 124 184 125 185 finish: 126 /* Unreference any jobs in interrupted BFS queue*/186 /* Let user clean partially processed units */ 127 187 list_foreach_safe(units_fifo, cur_link, next_link) { 128 188 unit_t *u = list_get_instance(cur_link, unit_t, bfs_link); 129 job_del_ref(&u->bfs_job);189 ops->clean(u, arg); 130 190 list_remove(cur_link); 131 191 } 192 193 return rc; 194 } 195 196 static 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 */ 224 int 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 132 249 133 250 /* Clean after ourselves (BFS tag jobs) */ 134 251 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 61 61 link_t bfs_link; 62 62 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; 66 68 67 69 /** Job assigned to unit in transitional state */
Note:
See TracChangeset
for help on using the changeset viewer.