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 31 struct wsi_queue { 32 struct u_vector vector; 33 pthread_mutex_t mutex; 34 pthread_cond_t cond; 35 }; 36 37 static inline int 38 wsi_queue_init(struct wsi_queue *queue, int length) 39 { 40 int ret; 41 42 uint32_t length_pow2 = 4; 43 while (length_pow2 < length) 44 length_pow2 *= 2; 45 46 ret = u_vector_init(&queue->vector, sizeof(uint32_t), 47 sizeof(uint32_t) * length_pow2); 48 if (!ret) 49 return ENOMEM; 50 51 pthread_condattr_t condattr; 52 ret = pthread_condattr_init(&condattr); 53 if (ret) 54 goto fail_vector; 55 56 ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); 57 if (ret) 58 goto fail_condattr; 59 60 ret = pthread_cond_init(&queue->cond, &condattr); 61 if (ret) 62 goto fail_condattr; 63 64 ret = pthread_mutex_init(&queue->mutex, NULL); 65 if (ret) 66 goto fail_cond; 67 68 pthread_condattr_destroy(&condattr); 69 return 0; 70 71 fail_cond: 72 pthread_cond_destroy(&queue->cond); 73 fail_condattr: 74 pthread_condattr_destroy(&condattr); 75 fail_vector: 76 u_vector_finish(&queue->vector); 77 78 return ret; 79 } 80 81 static inline void 82 wsi_queue_destroy(struct wsi_queue *queue) 83 { 84 u_vector_finish(&queue->vector); 85 pthread_mutex_destroy(&queue->mutex); 86 pthread_cond_destroy(&queue->cond); 87 } 88 89 static inline void 90 wsi_queue_push(struct wsi_queue *queue, uint32_t index) 91 { 92 uint32_t *elem; 93 94 pthread_mutex_lock(&queue->mutex); 95 96 if (u_vector_length(&queue->vector) == 0) 97 pthread_cond_signal(&queue->cond); 98 99 elem = u_vector_add(&queue->vector); 100 *elem = index; 101 102 pthread_mutex_unlock(&queue->mutex); 103 } 104 105 #define NSEC_PER_SEC 1000000000 106 #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1) 107 108 static inline VkResult 109 wsi_queue_pull(struct wsi_queue *queue, uint32_t *index, uint64_t timeout) 110 { 111 VkResult result; 112 int32_t ret; 113 114 pthread_mutex_lock(&queue->mutex); 115 116 struct timespec now; 117 clock_gettime(CLOCK_MONOTONIC, &now); 118 119 uint32_t abs_nsec = now.tv_nsec + timeout % NSEC_PER_SEC; 120 uint64_t abs_sec = now.tv_sec + (abs_nsec / NSEC_PER_SEC) + 121 (timeout / NSEC_PER_SEC); 122 abs_nsec %= NSEC_PER_SEC; 123 124 /* Avoid roll-over in tv_sec on 32-bit systems if the user provided timeout 125 * is UINT64_MAX 126 */ 127 struct timespec abstime; 128 abstime.tv_nsec = abs_nsec; 129 abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec)); 130 131 while (u_vector_length(&queue->vector) == 0) { 132 ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &abstime); 133 if (ret == 0) { 134 continue; 135 } else if (ret == ETIMEDOUT) { 136 result = VK_TIMEOUT; 137 goto end; 138 } else { 139 /* Something went badly wrong */ 140 result = VK_ERROR_OUT_OF_DATE_KHR; 141 goto end; 142 } 143 } 144 145 uint32_t *elem = u_vector_remove(&queue->vector); 146 *index = *elem; 147 result = VK_SUCCESS; 148 149 end: 150 pthread_mutex_unlock(&queue->mutex); 151 152 return result; 153 } 154 155 #endif /* VULKAN_WSI_COMMON_QUEUE_H */ 156