101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2016 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#ifndef VULKAN_WSI_COMMON_QUEUE_H 2501e04c3fSmrg#define VULKAN_WSI_COMMON_QUEUE_H 2601e04c3fSmrg 2701e04c3fSmrg#include <time.h> 2801e04c3fSmrg#include <pthread.h> 2901e04c3fSmrg#include "util/u_vector.h" 3001e04c3fSmrg 3101e04c3fSmrgstruct wsi_queue { 3201e04c3fSmrg struct u_vector vector; 3301e04c3fSmrg pthread_mutex_t mutex; 3401e04c3fSmrg pthread_cond_t cond; 3501e04c3fSmrg}; 3601e04c3fSmrg 3701e04c3fSmrgstatic inline int 3801e04c3fSmrgwsi_queue_init(struct wsi_queue *queue, int length) 3901e04c3fSmrg{ 4001e04c3fSmrg int ret; 4101e04c3fSmrg 427ec681f3Smrg if (length < 4) 437ec681f3Smrg length = 4; 4401e04c3fSmrg 457ec681f3Smrg ret = u_vector_init(&queue->vector, length, sizeof(uint32_t)); 4601e04c3fSmrg if (!ret) 4701e04c3fSmrg return ENOMEM; 4801e04c3fSmrg 4901e04c3fSmrg pthread_condattr_t condattr; 5001e04c3fSmrg ret = pthread_condattr_init(&condattr); 5101e04c3fSmrg if (ret) 5201e04c3fSmrg goto fail_vector; 5301e04c3fSmrg 5401e04c3fSmrg ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); 5501e04c3fSmrg if (ret) 5601e04c3fSmrg goto fail_condattr; 5701e04c3fSmrg 5801e04c3fSmrg ret = pthread_cond_init(&queue->cond, &condattr); 5901e04c3fSmrg if (ret) 6001e04c3fSmrg goto fail_condattr; 6101e04c3fSmrg 6201e04c3fSmrg ret = pthread_mutex_init(&queue->mutex, NULL); 6301e04c3fSmrg if (ret) 6401e04c3fSmrg goto fail_cond; 6501e04c3fSmrg 6601e04c3fSmrg pthread_condattr_destroy(&condattr); 6701e04c3fSmrg return 0; 6801e04c3fSmrg 6901e04c3fSmrgfail_cond: 7001e04c3fSmrg pthread_cond_destroy(&queue->cond); 7101e04c3fSmrgfail_condattr: 7201e04c3fSmrg pthread_condattr_destroy(&condattr); 7301e04c3fSmrgfail_vector: 7401e04c3fSmrg u_vector_finish(&queue->vector); 7501e04c3fSmrg 7601e04c3fSmrg return ret; 7701e04c3fSmrg} 7801e04c3fSmrg 7901e04c3fSmrgstatic inline void 8001e04c3fSmrgwsi_queue_destroy(struct wsi_queue *queue) 8101e04c3fSmrg{ 8201e04c3fSmrg u_vector_finish(&queue->vector); 8301e04c3fSmrg pthread_mutex_destroy(&queue->mutex); 8401e04c3fSmrg pthread_cond_destroy(&queue->cond); 8501e04c3fSmrg} 8601e04c3fSmrg 8701e04c3fSmrgstatic inline void 8801e04c3fSmrgwsi_queue_push(struct wsi_queue *queue, uint32_t index) 8901e04c3fSmrg{ 9001e04c3fSmrg uint32_t *elem; 9101e04c3fSmrg 9201e04c3fSmrg pthread_mutex_lock(&queue->mutex); 9301e04c3fSmrg 9401e04c3fSmrg if (u_vector_length(&queue->vector) == 0) 9501e04c3fSmrg pthread_cond_signal(&queue->cond); 9601e04c3fSmrg 9701e04c3fSmrg elem = u_vector_add(&queue->vector); 9801e04c3fSmrg *elem = index; 9901e04c3fSmrg 10001e04c3fSmrg pthread_mutex_unlock(&queue->mutex); 10101e04c3fSmrg} 10201e04c3fSmrg 10301e04c3fSmrg#define NSEC_PER_SEC 1000000000 10401e04c3fSmrg#define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1) 10501e04c3fSmrg 10601e04c3fSmrgstatic inline VkResult 10701e04c3fSmrgwsi_queue_pull(struct wsi_queue *queue, uint32_t *index, uint64_t timeout) 10801e04c3fSmrg{ 10901e04c3fSmrg VkResult result; 11001e04c3fSmrg int32_t ret; 11101e04c3fSmrg 11201e04c3fSmrg pthread_mutex_lock(&queue->mutex); 11301e04c3fSmrg 11401e04c3fSmrg struct timespec now; 11501e04c3fSmrg clock_gettime(CLOCK_MONOTONIC, &now); 11601e04c3fSmrg 11701e04c3fSmrg uint32_t abs_nsec = now.tv_nsec + timeout % NSEC_PER_SEC; 11801e04c3fSmrg uint64_t abs_sec = now.tv_sec + (abs_nsec / NSEC_PER_SEC) + 11901e04c3fSmrg (timeout / NSEC_PER_SEC); 12001e04c3fSmrg abs_nsec %= NSEC_PER_SEC; 12101e04c3fSmrg 12201e04c3fSmrg /* Avoid roll-over in tv_sec on 32-bit systems if the user provided timeout 12301e04c3fSmrg * is UINT64_MAX 12401e04c3fSmrg */ 12501e04c3fSmrg struct timespec abstime; 12601e04c3fSmrg abstime.tv_nsec = abs_nsec; 12701e04c3fSmrg abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec)); 12801e04c3fSmrg 12901e04c3fSmrg while (u_vector_length(&queue->vector) == 0) { 13001e04c3fSmrg ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &abstime); 13101e04c3fSmrg if (ret == 0) { 13201e04c3fSmrg continue; 13301e04c3fSmrg } else if (ret == ETIMEDOUT) { 13401e04c3fSmrg result = VK_TIMEOUT; 13501e04c3fSmrg goto end; 13601e04c3fSmrg } else { 13701e04c3fSmrg /* Something went badly wrong */ 13801e04c3fSmrg result = VK_ERROR_OUT_OF_DATE_KHR; 13901e04c3fSmrg goto end; 14001e04c3fSmrg } 14101e04c3fSmrg } 14201e04c3fSmrg 14301e04c3fSmrg uint32_t *elem = u_vector_remove(&queue->vector); 14401e04c3fSmrg *index = *elem; 14501e04c3fSmrg result = VK_SUCCESS; 14601e04c3fSmrg 14701e04c3fSmrgend: 14801e04c3fSmrg pthread_mutex_unlock(&queue->mutex); 14901e04c3fSmrg 15001e04c3fSmrg return result; 15101e04c3fSmrg} 15201e04c3fSmrg 15301e04c3fSmrg#endif /* VULKAN_WSI_COMMON_QUEUE_H */ 154