⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bdbuf.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 4 页
字号:
        rtems_build_name('B', 'S', 'W', 'P'),        SWAPOUT_PRIORITY,        SWAPOUT_STACK_SIZE,         RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT,        RTEMS_DEFAULT_ATTRIBUTES,        &bd_ctx.swapout_task);    if (rc != RTEMS_SUCCESSFUL)    {        rtems_semaphore_delete(bd_ctx.flush_sema);        for (i = 0; i < size; i++)            bdbuf_release_pool(i);        free(bd_ctx.pool);        return rc;    }    rc = rtems_task_start(bd_ctx.swapout_task, bdbuf_swapout_task, 0);    if (rc != RTEMS_SUCCESSFUL)    {        rtems_task_delete(bd_ctx.swapout_task);        rtems_semaphore_delete(bd_ctx.flush_sema);        for (i = 0; i < size; i++)            bdbuf_release_pool(i);        free(bd_ctx.pool);        return rc;    }    return RTEMS_SUCCESSFUL;}/* find_or_assign_buffer -- *     Looks for buffer already assigned for this dev/block. If one is found *     obtain block buffer. If specified block already cached (i.e. there's *     block in the _modified_, or _recently_used_), return address *     of appropriate buffer descriptor and increment reference counter to 1.  *     If block is not cached, allocate new buffer and return it. Data  *     shouldn't be read to the buffer from media; buffer contains arbitrary  *     data. This primitive may be blocked if there are no free buffer  *     descriptors available and there are no unused non-modified (or  *     synchronized with media) buffers available. * * PARAMETERS: *     device - device number (constructed of major and minor device number *     block  - linear media block number *     ret_buf - address of the variable to store address of found descriptor * * RETURNS: *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully *     or error code if error is occured) * * SIDE EFFEECTS: *     bufget_sema may be obtained by this primitive * * NOTE: *     It is assumed that primitive invoked when thread preemption is disabled. */static rtems_status_codefind_or_assign_buffer(disk_device *dd,                      blkdev_bnum block,                       bdbuf_buffer **ret_buf){    bdbuf_buffer *bd_buf;    bdbuf_pool   *bd_pool;    rtems_status_code rc;    dev_t         device;    ISR_Level     level;    int blksize;    device = dd->dev;    bd_pool = bd_ctx.pool + dd->pool;    blksize = dd->block_size;again:    /* Looking for buffer descriptor used for this dev/block. */    bd_buf = avl_search(&bd_pool->tree, device, block);    if (bd_buf == NULL)    {        /* Try to obtain semaphore without waiting first. It is the most           frequent case when reasonable number of buffers configured. If            it is failed, obtain semaphore blocking on it. In this case            it should be checked that appropriate buffer hasn't been loaded            by another thread, because this thread is preempted */        rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0);        if (rc == RTEMS_UNSATISFIED)        {            rc = rtems_semaphore_obtain(bd_pool->bufget_sema,                                        RTEMS_WAIT, RTEMS_NO_TIMEOUT);            bd_buf = avl_search(&bd_pool->tree, device, block);            if (bd_buf != NULL)                rtems_semaphore_release(bd_pool->bufget_sema);        }    }        if (bd_buf == NULL)    {        /* Assign new buffer descriptor */        if (_Chain_Is_empty(&bd_pool->free))        {            bd_buf = (bdbuf_buffer *)Chain_Get(&bd_pool->lru);            if (bd_buf != NULL)            {                int avl_result;                 avl_result = avl_remove(&bd_pool->tree, bd_buf);                if (avl_result != 0)                {                    rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);                    return RTEMS_INTERNAL_ERROR;                }            }        }        else        {            bd_buf = (bdbuf_buffer *)Chain_Get(&(bd_pool->free));        }        if (bd_buf == NULL)        {            goto again;        }        else        {            bd_buf->dev = device;            bd_buf->block = block;#ifdef AVL_GPL            bd_buf->avl.link[0] = NULL;            bd_buf->avl.link[1] = NULL;#else            bd_buf->avl.left = NULL;            bd_buf->avl.right = NULL;#endif            bd_buf->use_count = 1;            bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE;            bd_buf->status = RTEMS_SUCCESSFUL;            if (avl_insert(&bd_pool->tree, bd_buf) != 0)            {                rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);                return RTEMS_INTERNAL_ERROR;            }            *ret_buf = bd_buf;            return RTEMS_SUCCESSFUL;        }    }    else    {        /* Buffer descriptor already assigned for this dev/block */        if (bd_buf->use_count == 0)        {            /* If we are removing from lru list, obtain the bufget_sema             * first. If we are removing from mod list, obtain flush sema.             * It should be obtained without blocking because we know             * that our buffer descriptor is in the list. */            if (bd_buf->modified)            {                rc = rtems_semaphore_obtain(bd_ctx.flush_sema,                                             RTEMS_NO_WAIT, 0);            }            else            {                rc = rtems_semaphore_obtain(bd_pool->bufget_sema,                                             RTEMS_NO_WAIT, 0);            }            /* It is possible that we couldn't obtain flush or bufget sema              * although buffer in the appropriate chain is available:             * semaphore may be released to swapout task, but this task              * actually did not start to process it. */            if (rc == RTEMS_UNSATISFIED)                rc = RTEMS_SUCCESSFUL;            if (rc != RTEMS_SUCCESSFUL)            {                rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY);                return RTEMS_INTERNAL_ERROR;            }            /* Buffer descriptor is linked to the lru or mod chain. Remove               it from there. */            Chain_Extract(&bd_buf->link);        }        bd_buf->use_count++;        while (bd_buf->in_progress != 0)        {            rtems_interrupt_disable(level);            _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,                              WATCHDOG_NO_TIMEOUT, level);        }                *ret_buf = bd_buf;        return RTEMS_SUCCESSFUL;    }}/* rtems_bdbuf_get -- *     Obtain block buffer. If specified block already cached (i.e. there's *     block in the _modified_, or _recently_used_), return address *     of appropriate buffer descriptor and increment reference counter to 1.  *     If block is not cached, allocate new buffer and return it. Data  *     shouldn't be read to the buffer from media; buffer may contains  *     arbitrary data. This primitive may be blocked if there are no free  *     buffer descriptors available and there are no unused non-modified  *     (or synchronized with media) buffers available. * * PARAMETERS: *     device - device number (constructed of major and minor device number) *     block  - linear media block number *     bd     - address of variable to store pointer to the buffer descriptor * * RETURNS: *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully *     or error code if error is occured) * * SIDE EFFECTS: *     bufget_sema semaphore obtained by this primitive. */rtems_status_codertems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd){    rtems_status_code rc;    disk_device *dd;    disk_device *pdd;    preemption_key key;    /*     * Convert logical dev/block to physical one     */    dd = rtems_disk_lookup(device);    if (dd == NULL)        return RTEMS_INVALID_ID;        if (block >= dd->size)    {        rtems_disk_release(dd);        return RTEMS_INVALID_NUMBER;    }        pdd = dd->phys_dev;    block += dd->start;    rtems_disk_release(dd);    DISABLE_PREEMPTION(key);    rc = find_or_assign_buffer(pdd, block, bd);    ENABLE_PREEMPTION(key);    if (rc != RTEMS_SUCCESSFUL)        return rc;    return RTEMS_SUCCESSFUL;}/* bdbuf_initialize_transfer_sema -- *     Initialize transfer_sema mutex semaphore associated with buffer *     descriptor. */static inline voidbdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf){    CORE_mutex_Attributes mutex_attr;    mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS;    mutex_attr.only_owner_release = FALSE;    mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO;    mutex_attr.priority_ceiling = 0;    _CORE_mutex_Initialize(&bd_buf->transfer_sema,                            &mutex_attr, CORE_MUTEX_LOCKED);}/* bdbuf_write_transfer_done -- *     Callout function. Invoked by block device driver when data transfer *     to device (write) is completed. This function may be invoked from *     interrupt handler. * * PARAMETERS: *     arg    - arbitrary argument specified in block device request *              structure (in this case - pointer to the appropriate *              bdbuf_buffer buffer descriptor structure). *     status - I/O completion status *     error  - errno error code if status != RTEMS_SUCCESSFUL * * RETURNS: *     none */static voidbdbuf_write_transfer_done(void *arg, rtems_status_code status, int error){    bdbuf_buffer *bd_buf = arg;    bd_buf->status = status;    bd_buf->error = RTEMS_IO_ERROR;    bd_buf->in_progress = bd_buf->modified = FALSE;    _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);    _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,                       CORE_MUTEX_STATUS_SUCCESSFUL);}/* bdbuf_read_transfer_done -- *     Callout function. Invoked by block device driver when data transfer *     from device (read) is completed. This function may be invoked from *     interrupt handler. * * PARAMETERS: *     arg    - arbitrary argument specified in block device request *              structure (in this case - pointer to the appropriate *              bdbuf_buffer buffer descriptor structure). *     status - I/O completion status *     error  - errno error code if status != RTEMS_SUCCESSFUL * * RETURNS: *     none */static voidbdbuf_read_transfer_done(void *arg, rtems_status_code status, int error){    bdbuf_buffer *bd_buf = arg;    bd_buf->status = status;    bd_buf->error = RTEMS_IO_ERROR;    _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL);    _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL,                       CORE_MUTEX_STATUS_SUCCESSFUL);}/* rtems_bdbuf_read -- *     (Similar to the rtems_bdbuf_get, except reading data from media) *     Obtain block buffer. If specified block already cached, return address *     of appropriate buffer and increment reference counter to 1. If block is *     not cached, allocate new buffer and read data to it from the media. *     This primitive may be blocked on waiting until data to be read from *     media, if there are no free buffer descriptors available and there are *     no unused non-modified (or synchronized with media) buffers available. * * PARAMETERS: *     device - device number (consists of major and minor device number) *     block  - linear media block number *     bd     - address of variable to store pointer to the buffer descriptor * * RETURNS: *     RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully *     or error code if error is occured) * * SIDE EFFECTS: *     bufget_sema and transfer_sema semaphores obtained by this primitive. */rtems_status_codertems_bdbuf_read(dev_t device,                  blkdev_bnum block,                 bdbuf_buffer **bd){    preemption_key key;    ISR_Level level;        bdbuf_buffer *bd_buf;    rtems_status_code rc;    int result;    disk_device *dd;    disk_device *pdd;    blkdev_request1 req;    dd = rtems_disk_lookup(device);    if (dd == NULL)        return RTEMS_INVALID_ID;         if (block >= dd->size)    {        rtems_disk_release(dd);        return RTEMS_INVALID_NUMBER;    }        pdd = dd->phys_dev;    block += dd->start;    DISABLE_PREEMPTION(key);    rc = find_or_assign_buffer(pdd, block, &bd_buf);    if (rc != RTEMS_SUCCESSFUL)    {        ENABLE_PREEMPTION(key);        rtems_disk_release(dd);        return rc;    }    if (!bd_buf->actual)    {        bd_buf->in_progress = 1;        req.req.req = BLKDEV_REQ_READ;        req.req.req_done = bdbuf_read_transfer_done;        req.req.done_arg = bd_buf;        req.req.start = block;        req.req.count = 1;        req.req.bufnum = 1;        req.req.bufs[0].length = dd->block_size;        req.req.bufs[0].buffer = bd_buf->buffer;                bdbuf_initialize_transfer_sema(bd_buf);        result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req);        if (result == -1)        {            bd_buf->status = RTEMS_IO_ERROR;            bd_buf->error = errno;            bd_buf->actual = FALSE;        }        else        {            rtems_interrupt_disable(level);            _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE,                              WATCHDOG_NO_TIMEOUT, level);            bd_buf->actual = TRUE;        }        bd_buf->in_progress = FALSE;    }    rtems_disk_release(dd);        ENABLE_PREEMPTION(key);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -