/*
* Copyright © 2012 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
*/
#include
#include
#include
#include "cl_command_queue.h"
#include "cl_alloc.h"
#include "cl_mutex.h"
#include "cl_internals.h"
#include "cl_driver.h"
#include "cl_context.h"
#include "cl_device_id.h"
#include "cl_platform_id.h"
#include "cl_device_id.h"
static cl_int cl_flush(cl_command_queue queue)
{
cl_int err = CL_SUCCESS;
err = cl_enqueue_wait_for_flush(queue);
return err;
}
static cl_int cl_finish(cl_command_queue queue)
{
cl_int err = CL_SUCCESS;
err = cl_enqueue_wait_for_finish(queue);
return err;
}
static cl_command_queue cl_command_queue_new(cl_context ctx, cl_device_id device,
cl_command_queue_properties properties)
{
cl_command_queue queue = NULL;
queue = CL_CALLOC(1, sizeof(_cl_command_queue));
if (queue == NULL)
return NULL;
queue->magic = CL_MAGIC_QUEUE_HEADER;
cl_ref_set_val(&queue->ref_n, 1);
queue->ctx = ctx;
queue->device = device;
queue->props = properties;
/* The queue also belongs to its context */
cl_retain_context(ctx);
cl_retain_device_id(device);
/* Append the command queue in the list */
CL_MUTEX_LOCK(&ctx->lock);
queue->next = ctx->queues;
if (ctx->queues != NULL)
ctx->queues->prev = queue;
ctx->queues = queue;
CL_MUTEX_UNLOCK(&ctx->lock);
return queue;
}
static void cl_command_queue_delete(cl_command_queue queue)
{
assert(queue);
assert(queue->ctx);
assert(queue->device);
CL_MUTEX_LOCK(&queue->ctx->lock);
if (queue->prev)
queue->prev->next = queue->next;
if (queue->next)
queue->next->prev = queue->prev;
if (queue->ctx->queues == queue)
queue->ctx->queues = queue->next;
CL_MUTEX_UNLOCK(&queue->ctx->lock);
cl_release_context(queue->ctx);
cl_release_device_id(queue->device);
CL_FREE(queue->wait_events);
queue->magic = CL_MAGIC_DEAD_HEADER; /* For safety */
CL_FREE(queue);
}
LOCAL void cl_release_command_queue(cl_command_queue queue)
{
assert(queue);
cl_flush(queue);
if (cl_ref_dec(&queue->ref_n) > 1)
return;
cl_finish(queue);
/* Remove it from the list */
assert(queue->ctx);
assert(queue->device);
queue->device->driver->release_command_queue(queue);
cl_command_queue_worker_destroy(queue);
cl_command_queue_delete(queue);
}
static cl_command_queue cl_create_command_queue(cl_context ctx, cl_device_id device,
cl_command_queue_properties properties, cl_int *errcode_ret)
{
cl_command_queue queue = NULL;
cl_int err = CL_SUCCESS;
assert(ctx);
queue = cl_command_queue_new(ctx, device, properties);
if (queue == NULL) {
err = CL_OUT_OF_HOST_MEMORY;
goto exit;
}
err = cl_command_queue_worker_init(queue);
if (err != CL_SUCCESS) {
cl_command_queue_delete(queue);
queue = NULL;
goto exit;
}
err = queue->device->driver->create_command_queue(queue);
if (err != CL_SUCCESS) {
cl_command_queue_delete(queue);
queue = NULL;
goto exit;
}
exit:
if (errcode_ret)
*errcode_ret = err;
return queue;
}
LOCAL cl_int cl_retain_command_queue(cl_command_queue queue)
{
assert(queue);
int ret = cl_ref_inc_if_positive(&queue->ref_n);
if (ret > 0)
return ret;
return 0;
}
/**************************************************************************************
************************* CL APIs ********************************
**************************************************************************************/
cl_command_queue
clCreateCommandQueue(cl_context context,
cl_device_id device,
cl_command_queue_properties properties,
cl_int * errcode_ret)
{
cl_command_queue queue = NULL;
cl_int err = CL_SUCCESS;
int find_dev = 0;
int i = 0;
CHECK_CONTEXT(context);
CHECK_DEVICE(device);
for (i = 0; i < context->device_num; i++) {
if (device == context->devices[i]) {
find_dev = 1;
break;
}
}
INVALID_DEVICE_IF(!find_dev);
INVALID_VALUE_IF(properties & ~(CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_PROFILING_ENABLE));
if(properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) {/*not supported now.*/
err = CL_INVALID_QUEUE_PROPERTIES;
goto error;
}
queue = cl_create_command_queue(context, device, properties, &err);
error:
if (errcode_ret)
*errcode_ret = err;
return queue;
}
cl_int
clRetainCommandQueue(cl_command_queue command_queue)
{
cl_int err = CL_SUCCESS;
CHECK_QUEUE(command_queue);
if (cl_retain_command_queue(command_queue) == 0) {
err = CL_INVALID_COMMAND_QUEUE;
}
error:
return err;
}
cl_int
clReleaseCommandQueue(cl_command_queue command_queue)
{
cl_int err = CL_SUCCESS;
CHECK_QUEUE(command_queue);
cl_release_command_queue(command_queue);
error:
return err;
}
cl_int
clGetCommandQueueInfo(cl_command_queue command_queue,
cl_command_queue_info param_name,
size_t param_value_size,
void * param_value,
size_t * param_value_size_ret)
{
cl_int err = CL_SUCCESS;
CHECK_QUEUE (command_queue);
if (param_name == CL_QUEUE_CONTEXT) {
FILL_GETINFO_RET(cl_context, 1, &command_queue->ctx, CL_SUCCESS);
} else if (param_name == CL_QUEUE_DEVICE) {
FILL_GETINFO_RET(cl_device_id, 1, &command_queue->device, CL_SUCCESS);
} else if (param_name == CL_QUEUE_REFERENCE_COUNT) {
cl_uint ref = cl_ref_get_val(&command_queue->ref_n);
FILL_GETINFO_RET(cl_uint, 1, &ref, CL_SUCCESS);
} else if (param_name == CL_QUEUE_PROPERTIES) {
FILL_GETINFO_RET(cl_command_queue_properties, 1, &command_queue->props, CL_SUCCESS);
} else {
return CL_INVALID_VALUE;
}
error:
return err;
}
cl_int
clFlush(cl_command_queue command_queue)
{
cl_int err = CL_SUCCESS;
CHECK_QUEUE (command_queue);
err = cl_flush(command_queue);
error:
return err;
}
cl_int
clFinish(cl_command_queue command_queue)
{
cl_int err = CL_SUCCESS;
CHECK_QUEUE (command_queue);
err = cl_finish(command_queue);
error:
return err;
}