Changeset 0d56712 in mainline for kernel/generic/src/synch/workqueue.c


Ignore:
Timestamp:
2012-07-07T00:27:01Z (12 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
ff90f5f
Parents:
8a64e81e
Message:

workq: Added magic cookie integrity checks. Fixed test workqueue1.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/synch/workqueue.c

    r8a64e81e r0d56712  
    99#include <macros.h>
    1010
     11#define WORKQ_MAGIC      0xf00c1333U
     12#define WORK_ITEM_MAGIC  0xfeec1777U
     13
    1114
    1215struct work_queue {
     
    4649       
    4750        link_t nb_link;
     51       
     52#ifdef CONFIG_DEBUG
     53        /* Magic cookie for integrity checks. Immutable. Accessed without lock. */
     54        uint32_t cookie;
     55#endif
    4856};
    4957
     
    7987
    8088
    81 
    8289/* Fwd decl. */
    8390static void workq_preinit(struct work_queue *workq, const char *name);
     
    8794static int _workq_enqueue(struct work_queue *workq, work_t *work_item,
    8895        work_func_t func, bool can_block);
     96static void init_work_item(work_t *work_item, work_func_t func);
    8997static signal_op_t signal_worker_logic(struct work_queue *workq, bool can_block);
    9098static void worker_thread(void *arg);
     
    93101static void cv_wait(struct work_queue *workq);
    94102static void nonblock_init(void);
     103static bool workq_corrupted(struct work_queue *workq);
     104static bool work_item_corrupted(work_t *work_item);
     105
    95106
    96107/** Creates worker thread for the system-wide worker queue. */
     
    138149        if (workq) {
    139150                if (workq_init(workq, name)) {
     151                        ASSERT(!workq_corrupted(workq));
    140152                        return workq;
    141153                }
     
    150162void workq_destroy(struct work_queue *workq)
    151163{
    152         ASSERT(workq);
     164        ASSERT(!workq_corrupted(workq));
    153165       
    154166        irq_spinlock_lock(&workq->lock, true);
     
    163175        }
    164176       
     177#ifdef CONFIG_DEBUG
     178        workq->cookie = 0;
     179#endif
     180       
    165181        free(workq);
    166182}
     
    169185static void workq_preinit(struct work_queue *workq, const char *name)
    170186{
     187#ifdef CONFIG_DEBUG
     188        workq->cookie = WORKQ_MAGIC;
     189#endif
     190       
    171191        irq_spinlock_initialize(&workq->lock, name);
    172192        condvar_initialize(&workq->activate_worker);
     
    202222static bool add_worker(struct work_queue *workq)
    203223{
     224        ASSERT(!workq_corrupted(workq));
     225
    204226        thread_t *thread = thread_create(worker_thread, workq, TASK,
    205227                THREAD_FLAG_NONE, workq->name);
     
    270292void workq_stop(struct work_queue *workq)
    271293{
     294        ASSERT(!workq_corrupted(workq));
     295       
    272296        interrupt_workers(workq);
    273297        wait_for_workers(workq);
     
    285309        /* Respect lock ordering - do not hold workq->lock during broadcast. */
    286310        irq_spinlock_unlock(&workq->lock, true);
    287        
    288311       
    289312        condvar_broadcast(&workq->activate_worker);
     
    408431        work_func_t func, bool can_block)
    409432{
     433        ASSERT(!workq_corrupted(workq));
     434       
    410435        bool success = true;
    411436        signal_op_t signal_op = NULL;
    412        
    413         link_initialize(&work_item->queue_link);
    414         work_item->func = func;
    415437       
    416438        irq_spinlock_lock(&workq->lock, true);
     
    419441                success = false;
    420442        } else {
     443                init_work_item(work_item, func);
    421444                list_append(&work_item->queue_link, &workq->queue);
    422445                ++workq->item_cnt;
     
    442465}
    443466
     467/** Prepare an item to be added to the work item queue. */
     468static void init_work_item(work_t *work_item, work_func_t func)
     469{
     470#ifdef CONFIG_DEBUG
     471        work_item->cookie = WORK_ITEM_MAGIC;
     472#endif
     473       
     474        link_initialize(&work_item->queue_link);
     475        work_item->func = func;
     476}
     477
    444478/** Returns the number of workers running work func() that are not blocked. */
    445479static size_t active_workers_now(struct work_queue *workq)
     
    497531static void signal_worker_op(struct work_queue *workq)
    498532{
     533        ASSERT(!workq_corrupted(workq));
     534
    499535        condvar_signal(&workq->activate_worker);
    500536       
     
    515551static signal_op_t signal_worker_logic(struct work_queue *workq, bool can_block)
    516552{
     553        ASSERT(!workq_corrupted(workq));
    517554        ASSERT(irq_spinlock_locked(&workq->lock));
    518555       
     
    610647                /* Copy the func field so func() can safely free work_item. */
    611648                work_func_t func = work_item->func;
    612                
     649
    613650                func(work_item);
    614651        }
     
    618655static bool dequeue_work(struct work_queue *workq, work_t **pwork_item)
    619656{
     657        ASSERT(!workq_corrupted(workq));
     658       
    620659        irq_spinlock_lock(&workq->lock, true);
    621660       
     
    646685                link_t *work_link = list_first(&workq->queue);
    647686                *pwork_item = list_get_instance(work_link, work_t, queue_link);
     687               
     688#ifdef CONFIG_DEBUG
     689                ASSERT(!work_item_corrupted(*pwork_item));
     690                (*pwork_item)->cookie = 0;
     691#endif
    648692                list_remove(work_link);
    649693                --workq->item_cnt;
     
    694738                &workq->lock, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
    695739
     740        ASSERT(!workq_corrupted(workq));
    696741        ASSERT(irq_spinlock_locked(&workq->lock));
    697742       
     
    711756                /* Must be blocked in user work func() and not be waiting for work. */
    712757                ASSERT(!thread->workq_idling);
     758                ASSERT(thread->state == Sleeping);
    713759                ASSERT(THREAD != thread);
    714                 ASSERT(thread->state == Sleeping);
     760                ASSERT(!workq_corrupted(thread->workq));
    715761               
    716762                /* Protected by thread->lock */
     
    732778        if (THREAD->workq && THREAD->state == Sleeping && !THREAD->workq_idling) {
    733779                ASSERT(!THREAD->workq_blocked);
     780                ASSERT(!workq_corrupted(THREAD->workq));
     781               
    734782                THREAD->workq_blocked = true;
    735783               
     
    765813                (0 < workq->activate_pending) ? "increasing" : "stable";
    766814       
    767        
    768815        irq_spinlock_unlock(&workq->lock, true);
    769816       
    770817        printf(
    771                 "Configured with: max_worker_cnt=%zu, min_worker_cnt=%zu,\n"
    772                 "  max_concurrent_workers=%zu, max_items_per_worker=%zu\n"
     818                "Configuration: max_worker_cnt=%zu, min_worker_cnt=%zu,\n"
     819                " max_concurrent_workers=%zu, max_items_per_worker=%zu\n"
    773820                "Workers: %zu\n"
    774821                "Active:  %zu (workers currently processing work)\n"
     
    813860                *pworkq = list_get_instance(list_first(&info->work_queues),
    814861                        struct work_queue, nb_link);
     862
     863                ASSERT(!workq_corrupted(*pworkq));
    815864               
    816865                list_remove(&(*pworkq)->nb_link);
     
    835884static void nonblock_init(void)
    836885{
    837         irq_spinlock_initialize(&nonblock_adder.lock, "workq:nb.lock");
     886        irq_spinlock_initialize(&nonblock_adder.lock, "kworkq-nb.lock");
    838887        condvar_initialize(&nonblock_adder.req_cv);
    839888        list_initialize(&nonblock_adder.work_queues);
    840889       
    841890        nonblock_adder.thread = thread_create(thr_nonblock_add_worker,
    842                 &nonblock_adder, TASK, THREAD_FLAG_NONE, "workq:nb");
     891                &nonblock_adder, TASK, THREAD_FLAG_NONE, "kworkq-nb");
    843892       
    844893        if (nonblock_adder.thread) {
     
    849898                 * sleep, but at least boot the system.
    850899                 */
    851                 printf("Failed to create workq:nb. Sleeping work may stall the workq.\n");
    852         }
    853 }
    854 
    855 
     900                printf("Failed to create kworkq-nb. Sleeping work may stall the workq.\n");
     901        }
     902}
     903
     904/** Returns true if the workq is definitely corrupted; false if not sure.
     905 *
     906 * Can be used outside of any locks.
     907 */
     908static bool workq_corrupted(struct work_queue *workq)
     909{
     910#ifdef CONFIG_DEBUG
     911        /*
     912         * Needed to make the most current cookie value set by workq_preinit()
     913         * visible even if we access the workq right after it is created but
     914         * on a different cpu. Otherwise, workq_corrupted() would not work
     915         * outside a lock.
     916         */
     917        memory_barrier();
     918        return NULL == workq || workq->cookie != WORKQ_MAGIC;
     919#else
     920        return false;
     921#endif
     922}
     923
     924/** Returns true if the work_item is definitely corrupted; false if not sure.
     925 *
     926 * Must be used with the work queue protecting spinlock locked.
     927 */
     928static bool work_item_corrupted(work_t *work_item)
     929{
     930#ifdef CONFIG_DEBUG
     931        return NULL == work_item || work_item->cookie != WORK_ITEM_MAGIC;
     932#else
     933        return false;
     934#endif
     935}
Note: See TracChangeset for help on using the changeset viewer.