1/* 2 * Copyright © 2016 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#ifndef VULKAN_WSI_COMMON_QUEUE_H 25#define VULKAN_WSI_COMMON_QUEUE_H 26 27#include <time.h> 28#include <pthread.h> 29#include "util/u_vector.h" 30 31struct wsi_queue { 32 struct u_vector vector; 33 pthread_mutex_t mutex; 34 pthread_cond_t cond; 35}; 36 37static inline int 38wsi_queue_init(struct wsi_queue *queue, int length) 39{ 40 int ret; 41 42 if (length < 4) 43 length = 4; 44 45 ret = u_vector_init(&queue->vector, length, sizeof(uint32_t)); 46 if (!ret) 47 return ENOMEM; 48 49 pthread_condattr_t condattr; 50 ret = pthread_condattr_init(&condattr); 51 if (ret) 52 goto fail_vector; 53 54 ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); 55 if (ret) 56 goto fail_condattr; 57 58 ret = pthread_cond_init(&queue->cond, &condattr); 59 if (ret) 60 goto fail_condattr; 61 62 ret = pthread_mutex_init(&queue->mutex, NULL); 63 if (ret) 64 goto fail_cond; 65 66 pthread_condattr_destroy(&condattr); 67 return 0; 68 69fail_cond: 70 pthread_cond_destroy(&queue->cond); 71fail_condattr: 72 pthread_condattr_destroy(&condattr); 73fail_vector: 74 u_vector_finish(&queue->vector); 75 76 return ret; 77} 78 79static inline void 80wsi_queue_destroy(struct wsi_queue *queue) 81{ 82 u_vector_finish(&queue->vector); 83 pthread_mutex_destroy(&queue->mutex); 84 pthread_cond_destroy(&queue->cond); 85} 86 87static inline void 88wsi_queue_push(struct wsi_queue *queue, uint32_t index) 89{ 90 uint32_t *elem; 91 92 pthread_mutex_lock(&queue->mutex); 93 94 if (u_vector_length(&queue->vector) == 0) 95 pthread_cond_signal(&queue->cond); 96 97 elem = u_vector_add(&queue->vector); 98 *elem = index; 99 100 pthread_mutex_unlock(&queue->mutex); 101} 102 103#define NSEC_PER_SEC 1000000000 104#define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1) 105 106static inline VkResult 107wsi_queue_pull(struct wsi_queue *queue, uint32_t *index, uint64_t timeout) 108{ 109 VkResult result; 110 int32_t ret; 111 112 pthread_mutex_lock(&queue->mutex); 113 114 struct timespec now; 115 clock_gettime(CLOCK_MONOTONIC, &now); 116 117 uint32_t abs_nsec = now.tv_nsec + timeout % NSEC_PER_SEC; 118 uint64_t abs_sec = now.tv_sec + (abs_nsec / NSEC_PER_SEC) + 119 (timeout / NSEC_PER_SEC); 120 abs_nsec %= NSEC_PER_SEC; 121 122 /* Avoid roll-over in tv_sec on 32-bit systems if the user provided timeout 123 * is UINT64_MAX 124 */ 125 struct timespec abstime; 126 abstime.tv_nsec = abs_nsec; 127 abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec)); 128 129 while (u_vector_length(&queue->vector) == 0) { 130 ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &abstime); 131 if (ret == 0) { 132 continue; 133 } else if (ret == ETIMEDOUT) { 134 result = VK_TIMEOUT; 135 goto end; 136 } else { 137 /* Something went badly wrong */ 138 result = VK_ERROR_OUT_OF_DATE_KHR; 139 goto end; 140 } 141 } 142 143 uint32_t *elem = u_vector_remove(&queue->vector); 144 *index = *elem; 145 result = VK_SUCCESS; 146 147end: 148 pthread_mutex_unlock(&queue->mutex); 149 150 return result; 151} 152 153#endif /* VULKAN_WSI_COMMON_QUEUE_H */ 154