Changeset 8432ae1 in mainline


Ignore:
Timestamp:
2019-08-03T08:33:31Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
4b1c6a4b
Parents:
095d03c
git-author:
Michal Koutny <xm.koutny+hos@…> (2015-04-25 00:29:51)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-03 08:33:31)
Message:

sysman: Correct reference counting of jobs

Location:
uspace/srv/sysman
Files:
4 edited

Legend:

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

    r095d03c r8432ae1  
    4848                return ENOMEM;
    4949        }
    50 
    5150        job_add_ref(blocked_job);
     51
    5252        blocked_job->blocking_jobs += 1;
    5353
    5454        return EOK;
     55}
     56
     57/** Remove blocking_job from blocked job structure
     58 *
     59 * @note Caller must remove blocked_job from collection of blocked_jobs
     60 */
     61static void job_unblock(job_t *blocked_job, job_t *blocking_job)
     62{
     63        if (blocking_job->retval == JOB_FAILED) {
     64                blocked_job->blocking_job_failed = true;
     65        }
     66        blocked_job->blocking_jobs -= 1;
     67
     68        job_del_ref(&blocked_job);
    5569}
    5670
     
    6276        link_initialize(&job->job_queue);
    6377
    64         /* Start with one reference for the creator */
    65         atomic_set(&job->refcnt, 1);
     78        atomic_set(&job->refcnt, 0);
    6679
    6780        job->target_state = target_state;
     
    100113        job_t *job = data;
    101114
     115        /*
     116         * We have one reference from caller for our disposal,   *
     117         * if needed, pass it to observer.
     118         */
    102119        if (job_eval_retval(job)) {
    103120                job_finish(job);
     121                job_del_ref(&job);
    104122        } else {
    105123                // TODO place for timeout
    106                 // TODO add reference to job?
    107124                sysman_object_observer(u, &job_check, job);
    108125        }
     
    110127
    111128
    112 static void job_unblock(job_t *blocked_job, job_t *blocking_job)
    113 {
    114         if (blocking_job->retval == JOB_FAILED) {
    115                 blocked_job->blocking_job_failed = true;
    116         }
    117         blocked_job->blocking_jobs -= 1;
    118 }
     129
    119130
    120131static void job_destroy(job_t **job_ptr)
     
    126137
    127138        assert(!link_used(&job->job_queue));
     139
     140        dyn_array_foreach(job->blocked_jobs, job_ptr_t, job_it) {
     141                job_del_ref(&(*job_it));
     142        }
    128143        dyn_array_destroy(&job->blocked_jobs);
    129         // TODO I should decrease referece of blocked jobs
    130144
    131145        free(job);
     
    164178                (*job_it)->state = JOB_QUEUED;
    165179                list_append(&(*job_it)->job_queue, &job_queue);
    166                 // TODO explain this reference
    167                 job_add_ref(*job_it);
     180                /* We pass reference from the closure to the queue */
    168181        }
    169182
     
    203216
    204217        if (result) {
    205                 // TODO update refcount
     218                /* Remove job from queue and pass refernce to caller */
    206219                list_remove(&result->job_queue);
    207220                result->state = JOB_DEQUEUED;
     
    225238         * Traverse dependency graph in BFS fashion and create jobs for every
    226239         * necessary unit.
     240         * Closure keeps reference to each job. We've to add reference to the
     241         * main job, other newly created jobs are pased to the closure.
    227242         */
    228243        fifo_push(jobs_fifo, main_job);
    229244        job_t *job;
     245        job_add_ref(main_job);
    230246        while ((job = fifo_pop(jobs_fifo)) != NULL) {
    231                 /*
    232                  * Do not increase reference count of job, as we're passing it
    233                  * to the closure.
    234                  */
     247                /* No refcount increase, pass it to the closure */
    235248                dyn_array_append(job_closure, job_ptr_t, job);
    236249
     
    256269        /*
    257270         * Newly created jobs are already passed to the closure, thus not
    258          * deleting them here.
     271         * deleting reference to them here.
    259272         */
    260273        return rc;
     
    266279        if (job != NULL) {
    267280                job_init(job, u, target_state);
     281
     282                /* Start with one reference for the creator */
     283                job_add_ref(job);
    268284        }
    269285
     
    271287}
    272288
     289/** Add one reference to job
     290 *
     291 * Usage:
     292 *   - adding observer which references the job,
     293 *   - raising and event that references the job,
     294 *   - anytime any other new reference is made.
     295 */
    273296void job_add_ref(job_t *job)
    274297{
     
    276299}
    277300
     301/** Remove one reference from job, last remover destroys the job
     302 *
     303 * Usage:
     304 *   - inside observer callback that references the job,
     305 *   - inside event handler that references the job,
     306 *   - anytime you dispose a reference to the job.
     307 */
    278308void job_del_ref(job_t **job_ptr)
    279309{
    280310        job_t *job = *job_ptr;
    281         if (job == NULL) {
    282                 return;
    283         }
    284 
     311
     312        assert(job != NULL);
    285313        assert(atomic_get(&job->refcnt) > 0);
    286314        if (atomic_predec(&job->refcnt) == 0) {
     
    295323
    296324        unit_t *u = job->unit;
    297         sysman_log(LVL_DEBUG, "%s, %s -> %i",
    298             __func__, unit_name(u), job->target_state);
     325        sysman_log(LVL_DEBUG, "%s(%p), %s -> %i",
     326            __func__, job, unit_name(u), job->target_state);
    299327
    300328        /* Propagate failure */
     
    316344        }
    317345
     346        /*
     347         * job_check deletes reference, we want job to remain to caller, thus
     348         * add one dummy ref
     349         */
     350        job_add_ref(job);
    318351        job_check(job->unit, job);
    319352        return;
     
    333366        assert(job->retval != JOB_UNDEFINED_);
    334367
    335         sysman_log(LVL_DEBUG2, "%s(%s) -> %i",
    336             __func__, unit_name(job->unit), job->retval);
     368        sysman_log(LVL_DEBUG2, "%s(%p) %s -> %i",
     369            __func__, job, unit_name(job->unit), job->retval);
    337370
    338371        job->state = JOB_FINISHED;
    339372
    340         /* Job finished */
     373        /* First remove references, then clear the array */
    341374        dyn_array_foreach(job->blocked_jobs, job_ptr_t, job_it) {
    342375                job_unblock(*job_it, job);
    343376        }
    344         // TODO remove reference from blocked jobs
    345 
    346         // TODO should reference be added (for the created event)
     377        dyn_array_clear(&job->blocked_jobs);
     378
     379        /* Add reference for the event */
     380        job_add_ref(job);
    347381        sysman_raise_event(&sysman_event_job_changed, job);
    348382}
  • uspace/srv/sysman/job.h

    r095d03c r8432ae1  
    8585extern void job_del_ref(job_t **);
    8686
    87 
    8887extern void job_run(job_t *);
    8988extern void job_finish(job_t *);
  • uspace/srv/sysman/main.c

    r095d03c r8432ae1  
    149149
    150150        /* Queue first job for processing */
     151        job_add_ref(first_job);
    151152        sysman_object_observer(first_job, &first_job_handler, NULL);
     153        job_add_ref(first_job);
    152154        sysman_raise_event(&sysman_event_job_process, first_job);
     155       
     156        /*
     157         * Releasing our own reference (could be merged with previous add_ref,
     158         * this is more explicit though.
     159         */
     160        job_del_ref(&first_job);
    153161
    154162        /* Start sysman server */
  • uspace/srv/sysman/sysman.c

    r095d03c r8432ae1  
    150150
    151151                /* Process event */
     152                sysman_log(LVL_DEBUG2, "process(%p, %p)", event->handler, event->data);
    152153                event->handler(event->data);
    153154                free(event);
     
    157158void sysman_raise_event(event_handler_t handler, void *data)
    158159{
     160        sysman_log(LVL_DEBUG2, "%s(%p, %p)", __func__, handler, data);
    159161        event_t *event = malloc(sizeof(event_t));
    160162        if (event == NULL) {
     
    237239        }
    238240
     241        /*
     242         * If jobs are queued, reference is passed from closure to the queue,
     243         * otherwise, we still have the reference.
     244         */
    239245        rc = job_queue_add_jobs(&job_closure);
    240246        if (rc != EOK) {
    241                 // TODO job_queue_add_jobs should log message
    242247                goto fail;
    243248        }
     249        /* We don't need job anymore */
     250        job_del_ref(&job);
    244251
    245252        // TODO explain why calling asynchronously
     
    250257        job->retval = JOB_FAILED;
    251258        job_finish(job);
    252         // TODO clarify refcount to the main job
     259        job_del_ref(&job);
     260
    253261        dyn_array_foreach(job_closure, job_ptr_t, closure_job) {
    254262                job_del_ref(&(*closure_job));
     
    263271        while ((job = job_queue_pop_runnable())) {
    264272                job_run(job);
     273                job_del_ref(&job);
    265274        }
    266275}
     
    269278{
    270279        notify_observers(object);
    271 }
     280        /* Unreference the event data */
     281        job_t *job = object;
     282        job_del_ref(&job);
     283}
Note: See TracChangeset for help on using the changeset viewer.