/* * 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; }