Changeset dba056b in mainline


Ignore:
Timestamp:
2019-08-06T19:23:56Z (5 years ago)
Author:
Matthieu Riolo <matthieu.riolo@…>
Children:
c6d87c10
Parents:
3f05ef7
git-author:
Michal Koutný <xm.koutny+hos@…> (2015-06-20 01:04:31)
git-committer:
Matthieu Riolo <matthieu.riolo@…> (2019-08-06 19:23:56)
Message:

sysman: Using exposees to detect asynchronous start

  • also fixed bug with reference counting of merged jobs
  • add test for the faulty behavior
Location:
uspace/srv/sysman
Files:
5 edited

Legend:

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

    r3f05ef7 rdba056b  
    8080        assert(job);
    8181        assert(u);
    82         assert(u->job == NULL);
    8382        memset(job, 0, sizeof(*job));
    8483
     
    178177}
    179178
     179/** Add multiple references to job
     180 *
     181 * Non-atomicity doesn't mind as long as individual increments are atomic.
     182 *
     183 * @note Function is not exported as other modules shouldn't need it.
     184 */
     185static inline void job_add_refs(job_t *job, size_t refs)
     186{
     187        for (size_t i = 0; i < refs; ++i) {
     188                job_add_ref(job);
     189        }
     190}
     191
     192/** Delete multiple references to job
     193 *
     194 * Behavior of concurrent runs with job_add_refs aren't specified.
     195 */
     196static inline void job_del_refs(job_t **job_ptr, size_t refs)
     197{
     198        for (size_t i = 0; i < refs; ++i) {
     199                job_del_ref(job_ptr);
     200        }
     201}
     202
    180203/** Merge two jobs together
    181204 *
     
    212235        trunk->blocked_jobs_count = other->blocked_jobs.size;
    213236
    214         /* All allocation is done in job_pre_merge, cannot fail here. */
     237        /*
     238         * Note, the sysman_move_observers cannot fail here sice all necessary
     239         * allocation is done in job_pre_merge.
     240         */
     241        size_t observers_refs = sysman_observers_count(other);
    215242        int rc = sysman_move_observers(other, trunk);
    216243        assert(rc == EOK);
     244
     245        /* When we move observers, don't forget to pass their references too. */
     246        job_add_refs(trunk, observers_refs);
     247        job_del_refs(&other, observers_refs);
    217248}
    218249
     
    233264}
    234265
     266/** Consistenly add jobs to the queue
     267 *
     268 * @param[in/out]  closure    jobs closure, on success it's emptied, otherwise
     269 *                            you should take care of remaining jobs
     270 *
     271 * @return EOK on success
     272 * @return EBUSY when any job in closure is conflicting
     273 */
    235274int job_queue_add_closure(dyn_array_t *closure)
    236275{
     
    307346
    308347                unit_t *u = job->unit;
    309                 assert(u->bfs_job != NULL);
    310348                assert(u->job == NULL);
    311                 u->job = u->bfs_job;
    312                 u->bfs_job = NULL;
    313 
    314 
     349                /* Pass reference from the closure to the unit */
     350                u->job = job;
     351
     352                /* Enqueue job (new reference) */
    315353                job->state = JOB_PENDING;
    316                 /* We pass reference from the closure to the queue */
     354                job_add_ref(job);
    317355                list_append(&job->job_queue, &job_queue);
    318356        }
     357
     358        /* We've stolen references from the closure, so erase it */
     359        dyn_array_clear(closure);
    319360
    320361        return EOK;
     
    347388        /* Check invariant */
    348389        list_foreach(units, units, unit_t, u) {
    349                 assert(u->bfs_job == false);
     390                assert(u->bfs_job == NULL);
    350391        }
    351392               
     
    390431                }
    391432        }
    392 //      sysman_log(LVL_DEBUG2, "%s(%s):", __func__, unit_name(main_job->unit));
    393 //      dyn_array_foreach(*job_closure, job_t *, job_it) {
    394 //              sysman_log(LVL_DEBUG2, "%s\t%s", __func__, unit_name((*job_it)->unit));
    395 //      }
     433        sysman_log(LVL_DEBUG2, "%s(%s):", __func__, unit_name(main_job->unit));
     434        dyn_array_foreach(*job_closure, job_t *, job_it) {
     435                sysman_log(LVL_DEBUG2, "%s\t%s, refs: %u", __func__,
     436                    unit_name((*job_it)->unit), atomic_get(&(*job_it)->refcnt));
     437        }
    396438        rc = EOK;
    397439
     
    402444                job_del_ref(&u->bfs_job);
    403445                list_remove(cur_link);
     446        }
     447       
     448        /* Clean after ourselves (BFS tag jobs) */
     449        dyn_array_foreach(*job_closure, job_t *, job_it) {
     450                assert(*job_it == (*job_it)->unit->bfs_job);
     451                job_del_ref(&(*job_it)->unit->bfs_job);
     452                (*job_it)->unit->bfs_job = NULL;
    404453        }
    405454
     
    514563        assert(job->state != JOB_FINISHED);
    515564        assert(job->retval != JOB_UNDEFINED_);
    516         assert(job->unit->job == job);
    517 
    518         sysman_log(LVL_DEBUG2, "%s(%p) %s ret %i",
    519             __func__, job, unit_name(job->unit), job->retval);
     565        assert(!job->unit->job || job->unit->job == job);
     566
     567        sysman_log(LVL_DEBUG2, "%s(%p) %s ret %i, ref %i",
     568            __func__, job, unit_name(job->unit), job->retval,
     569            atomic_get(&job->refcnt));
    520570
    521571        job->state = JOB_FINISHED;
     
    528578        dyn_array_clear(&job->blocked_jobs);
    529579
    530         /*
    531          * Remove job from unit and pass the reference from the unit to the
    532          * event.
    533          */
    534         job->unit->job = NULL;
     580        /* Add reference for event handler */
     581        if (job->unit->job == NULL) {
     582                job_add_ref(job);
     583        } else {
     584                /* Pass reference from unit */
     585                job->unit->job = NULL;
     586        }
    535587        sysman_raise_event(&sysman_event_job_finished, job);
    536588}
  • uspace/srv/sysman/sysman.c

    r3f05ef7 rdba056b  
    196196/** Create and queue job for unit
    197197 *
    198  * If unit already has the same job assigned callback is set to it.
     198 * If unit already has the same job assigned callback is moved to it.
    199199 *
    200200 * @param[in]  callback  (optional) callback must explicitly delete reference
     
    213213        if (callback != NULL) {
    214214                job_add_ref(job);
     215                //TODO sysman_object_observer is not fibril-safe CANNOT BE CALLED HERE!
    215216                sysman_object_observer(job, callback, callback_arg);
    216217        }
     
    328329}
    329330
     331size_t sysman_observers_count(void *object)
     332{
     333        ht_link_t *ht_link = hash_table_find(&observed_objects, &object);
     334
     335        if (ht_link == NULL) {
     336                return 0;
     337        }
     338
     339        observed_object_t *observed_object =
     340            hash_table_get_inst(ht_link, observed_object_t, ht_link);
     341
     342        return list_count(&observed_object->callbacks);
     343}
     344
    330345
    331346/*
     
    355370                goto fail;
    356371        }
     372
    357373        /* We don't need job anymore */
    358374        job_del_ref(&job);
  • uspace/srv/sysman/sysman.h

    r3f05ef7 rdba056b  
    4545extern int sysman_object_observer(void *, callback_handler_t, void *);
    4646extern int sysman_move_observers(void *, void *);
     47extern size_t sysman_observers_count(void *);
    4748
    4849
  • uspace/srv/sysman/test/job_queue.c

    r3f05ef7 rdba056b  
    152152}
    153153
     154PCUT_TEST(merge_jobs_with_callback) {
     155        /* Setup mock behavior */
     156        unit_type_vmts[UNIT_SERVICE]->start = &mock_unit_vmt_start_async;
     157        unit_type_vmts[UNIT_SERVICE]->exposee_created =
     158            &mock_unit_vmt_exposee_created;
     159
     160        /* Define mock units */
     161        unit_t *s0 = mock_units[UNIT_SERVICE][0];
     162
     163        /* Create and start first job */
     164        job_t *j0 = NULL;
     165        int rc = sysman_run_job(s0, STATE_STARTED, &job_finished_cb, &j0);
     166        PCUT_ASSERT_INT_EQUALS(EOK, rc);
     167
     168        sysman_process_queue();
     169        /* Job not finished */
     170        PCUT_ASSERT_NULL(j0);
     171
     172
     173        /*
     174         * While s0 is starting in j0, create second job that should be merged
     175         * into the existing one.
     176         */
     177        job_t *j1 = NULL;
     178        rc = sysman_run_job(s0, STATE_STARTED, &job_finished_cb, &j1);
     179        PCUT_ASSERT_INT_EQUALS(EOK, rc);
     180
     181        sysman_process_queue();
     182        /* Job not finished */
     183        PCUT_ASSERT_NULL(j1);
     184
     185        sysman_raise_event(&sysman_event_unit_exposee_created, s0);
     186        sysman_process_queue();
     187
     188        PCUT_ASSERT_NOT_NULL(j0);
     189        PCUT_ASSERT_NOT_NULL(j1);
     190       
     191        /*
     192         * Jobs were, merged so both callbacks should have been called with the
     193         * same job
     194         */
     195        PCUT_ASSERT_EQUALS(j0, j1);
     196
     197        /* And there should be exactly two references (per each callback) */
     198        job_del_ref(&j0);
     199        job_del_ref(&j0);
     200
     201        PCUT_ASSERT_NULL(j0);
     202}
     203
    154204
    155205PCUT_EXPORT(job_queue);
  • uspace/srv/sysman/units/unit_svc.c

    r3f05ef7 rdba056b  
    100100         * in a moment. Applies to naming service only.
    101101         */
    102         // TODO this is even hack in the workaround, exposees doesn't work properly
    103         if (true || str_cmp(unit->name, "devman.svc") == 0 ||
     102        if (str_cmp(unit->name, "devman.svc") == 0 ||
    104103            str_cmp(unit->name, "logger.svc") == 0 ||
    105104            str_cmp(unit->name, "irc.svc") == 0) {
Note: See TracChangeset for help on using the changeset viewer.