On Sun, Oct 22, 2017 at 9:33 PM, Nicolai Hähnle <nhaeh...@gmail.com> wrote:
> From: Nicolai Hähnle <nicolai.haeh...@amd.com>
>
> Fences are now 4 bytes instead of 96 bytes (on my 64-bit system).
>
> Signaling a fence is a single atomic operation in the fast case plus a
> syscall in the slow case.
>
> Testing if a fence is signaled is the same as before (a simple comparison),
> but waiting on a fence is now no more expensive than just testing it in
> the fast (already signaled) case.
> ---
>  src/util/futex.h   |  4 +++
>  src/util/u_queue.c |  2 ++
>  src/util/u_queue.h | 88 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 94 insertions(+)
>
> ...
>
> diff --git a/src/util/u_queue.h b/src/util/u_queue.h
> index a3e12260e30..3d9f19f4e6c 100644
> --- a/src/util/u_queue.h
> +++ b/src/util/u_queue.h
> @@ -28,30 +28,117 @@
>   *
>   * Jobs can be added from any thread. After that, the wait call can be used
>   * to wait for completion of the job.
>   */
>
>  #ifndef U_QUEUE_H
>  #define U_QUEUE_H
>
>  #include <string.h>
>
> +#include "util/futex.h"
>  #include "util/list.h"
> +#include "util/macros.h"
>  #include "util/u_thread.h"
>
>  #ifdef __cplusplus
>  extern "C" {
>  #endif
>
>  #define UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY      (1 << 0)
>  #define UTIL_QUEUE_INIT_RESIZE_IF_FULL            (1 << 1)
>
> +#if defined(__GNUC__) && defined(HAVE_FUTEX)
> +#define UTIL_QUEUE_FENCE_FUTEX
> +#else
> +#define UTIL_QUEUE_FENCE_STANDARD
> +#endif
> +
> +#ifdef UTIL_QUEUE_FENCE_FUTEX
> +/* Job completion fence.
> + * Put this into your job structure.
> + */
> +struct util_queue_fence {
> +   /* The fence can be in one of three states:
> +    *  0 - signaled
> +    *  1 - unsignaled
> +    *  2 - unsignaled, may have waiters
> +    */
> +   uint32_t val;
> +};
> +
> +static inline void
> +util_queue_fence_init(struct util_queue_fence *fence)
> +{
> +   fence->val = 0;
> +}
> +
> +static inline void
> +util_queue_fence_destroy(struct util_queue_fence *fence)
> +{
> +   assert(fence->val == 0);
> +   /* no-op */
> +}
> +
> +static inline void
> +util_queue_fence_wait(struct util_queue_fence *fence)
> +{
> +   uint32_t v = fence->val;
> +
> +   if (likely(v == 0))
> +      return;
> +
> +   do {
> +      if (v != 2)
> +         v = __sync_val_compare_and_swap(&fence->val, 1, 2);
> +
> +      futex_wait(&fence->val, 2);
> +      v = fence->val;
> +   } while(v != 0);
> +}
> +
> +static inline void
> +util_queue_fence_signal(struct util_queue_fence *fence)
> +{
> +   uint32_t val = __sync_lock_test_and_set(&fence->val, 0);

As this is _signal(), don't you need a full barrier here?

> +
> +   assert(val != 0);
> +
> +   if (val == 2)

The documentation says some architectures may only support a constant
of 1 here...

> +      futex_wake_all(&fence->val);
> +}

Gražvydas
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to