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