~jamesodhunt/ubuntu/saucy/upstart/bug-1124384

« back to all changes in this revision

Viewing changes to init/job_class.c

  • Committer: James Hunt
  • Date: 2013-04-30 21:59:20 UTC
  • mfrom: (1182.56.81 upstart-bug-1124384)
  • Revision ID: james.hunt@ubuntu.com-20130430215920-uve839b5lx6tie3m
cherry-pick fix for LP: #1124384 to preserve event blockers during
reload.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 *
3
3
 * job_class.c - job class definition handling
4
4
 *
5
 
 * Copyright © 2011 Canonical Ltd.
 
5
 * Copyright  2011 Canonical Ltd.
6
6
 * Author: Scott James Remnant <scott@netsplit.com>.
7
7
 *
8
8
 * This program is free software; you can redistribute it and/or modify
369
369
        return NULL;
370
370
}
371
371
 
 
372
/**
 
373
 * job_class_get_registered:
 
374
 *
 
375
 * @name: name of JobClass to search for,
 
376
 * @session: Session of @class.
 
377
 *
 
378
 * Determine the currently registered JobClass with name @name for
 
379
 * session @session.
 
380
 *
 
381
 * Returns: JobClass or NULL if no JobClass with name @name and
 
382
 * session @session is registered.
 
383
 **/
 
384
JobClass *
 
385
job_class_get_registered (const char *name, Session *session)
 
386
{
 
387
        JobClass *registered;
 
388
 
 
389
        nih_assert (name);
 
390
 
 
391
        job_class_init ();
 
392
 
 
393
        registered = (JobClass *)nih_hash_search (job_classes, name, NULL);
 
394
 
 
395
        /* If we found an entry, ensure we only consider the appropriate session */
 
396
        while (registered && registered->session != session)
 
397
                registered = (JobClass *)nih_hash_search (job_classes, name, &registered->entry);
 
398
 
 
399
        return registered;
 
400
}
372
401
 
373
402
/**
374
403
 * job_class_consider:
383
412
int
384
413
job_class_consider (JobClass *class)
385
414
{
386
 
        JobClass *registered = NULL, *best = NULL;
 
415
        JobClass           *registered = NULL;
 
416
        JobClass           *best = NULL;
387
417
 
388
418
        nih_assert (class != NULL);
389
419
 
393
423
        nih_assert (best != NULL);
394
424
        nih_assert (best->session == class->session);
395
425
 
396
 
        registered = (JobClass *)nih_hash_search (job_classes, class->name, NULL);
397
 
 
398
 
        /* If we found an entry, ensure we only consider the appropriate session */
399
 
        while (registered && registered->session != class->session)
400
 
                registered = (JobClass *)nih_hash_search (job_classes, class->name, &registered->entry);
 
426
        registered = job_class_get_registered (class->name, class->session);
401
427
 
402
428
        if (registered != best) {
403
 
                if (registered)
404
 
                        if (! job_class_remove (registered, class->session))
 
429
                if (registered) {
 
430
                        job_class_event_block (NULL, registered, best);
 
431
 
 
432
                        if (! job_class_remove (registered, class->session)) {
 
433
                                /* Couldn't deregister, so undo */
 
434
                                if (best->start_on)
 
435
                                        event_operator_reset (best->start_on);
405
436
                                return FALSE;
 
437
                        }
 
438
                }
406
439
 
407
440
                job_class_add (best);
408
441
        }
426
459
int
427
460
job_class_reconsider (JobClass *class)
428
461
{
429
 
        JobClass *registered = NULL, *best = NULL;
 
462
        JobClass           *registered = NULL;
 
463
        JobClass           *best = NULL;
430
464
 
431
465
        nih_assert (class != NULL);
432
466
 
434
468
 
435
469
        best = conf_select_job (class->name, class->session);
436
470
 
437
 
        registered = (JobClass *)nih_hash_search (job_classes, class->name, NULL);
438
 
 
439
 
        /* If we found an entry, ensure we only consider the appropriate session */
440
 
        while (registered && registered->session != class->session)
441
 
                registered = (JobClass *)nih_hash_search (job_classes, class->name, &registered->entry);
 
471
        registered = job_class_get_registered (class->name, class->session);
442
472
 
443
473
        if (registered == class) {
444
474
                if (class != best) {
457
487
}
458
488
 
459
489
/**
 
490
 * job_class_event_block:
 
491
 *
 
492
 * @parent: parent object for list,
 
493
 * @old: original JobClass currently registered in job_classes,
 
494
 * @new: new "best" JobClass that is not yet present in job_classes.
 
495
 *
 
496
 * Compare @old and @new start on EventOperator trees looking for
 
497
 * matching events that occur in both (_and_ which implicitly still exist
 
498
 * in the global events list). Events that satisfy these criteria will have
 
499
 * their reference count elevated to allow @new to replace @old in job_classes
 
500
 * without the destruction of @old freeing the events in question.
 
501
 *
 
502
 * Note that the reference count never needs to be decremented back
 
503
 * again since this function effectively passes "ownership" of the event
 
504
 * block from @old to @new, since @old will be replaced by @new but @new
 
505
 * should replicate the EventOperator state of @old.
 
506
 **/
 
507
void
 
508
job_class_event_block (void *parent, JobClass *old, JobClass *new)
 
509
{
 
510
        EventOperator  *old_root;
 
511
        EventOperator  *new_root;
 
512
 
 
513
        if (! old || ! new)
 
514
                return;
 
515
 
 
516
        old_root = old->start_on;
 
517
        new_root = new->start_on;
 
518
 
 
519
        /* If either @old or @new are NULL, or have no start_on
 
520
         * condition, there is no need to modify any events.
 
521
         */
 
522
        if (! old_root || ! new_root)
 
523
                return;
 
524
 
 
525
        /* The old JobClass has associated instances meaning it 
 
526
         * will not be possible for job_class_remove() to replace it, so
 
527
         * we don't need to manipulate any event reference counts.
 
528
         */
 
529
        NIH_HASH_FOREACH (old->instances, iter)
 
530
                return;
 
531
 
 
532
        NIH_TREE_FOREACH_POST (&old_root->node, iter) {
 
533
                EventOperator  *old_oper = (EventOperator *)iter;
 
534
                Event          *event;
 
535
 
 
536
                if (old_oper->type != EVENT_MATCH)
 
537
                        continue;
 
538
 
 
539
                /* Ignore nodes that are not blocking events */
 
540
                if (! old_oper->event)
 
541
                        continue;
 
542
 
 
543
                /* Since the JobClass is blocking an event,
 
544
                 * that event must be valid.
 
545
                 */
 
546
                event = old_oper->event;
 
547
 
 
548
                NIH_TREE_FOREACH_POST (&new_root->node, niter) {
 
549
                        EventOperator *new_oper = (EventOperator *)niter;
 
550
 
 
551
                        if (new_oper->type != EVENT_MATCH)
 
552
                                continue;
 
553
 
 
554
                        /* ignore the return - we just want to ensure
 
555
                         * that any events in @new that match those in
 
556
                         * @old have identical nodes.
 
557
                         */
 
558
                        (void)event_operator_handle (new_oper, event, NULL);
 
559
                }
 
560
        }
 
561
}
 
562
 
 
563
/**
460
564
 * job_class_add:
461
565
 * @class: new class to select.
462
566
 *