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