freedreno: replace all dup() with os_dupfd_cloexec()
[mesa.git] / src / gallium / drivers / freedreno / freedreno_fence.c
1 /*
2 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
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 FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Rob Clark <robclark@freedesktop.org>
25 */
26
27 #include <libsync.h>
28
29 #include "util/os_file.h"
30 #include "util/u_inlines.h"
31
32 #include "freedreno_fence.h"
33 #include "freedreno_context.h"
34 #include "freedreno_util.h"
35
36 struct pipe_fence_handle {
37 struct pipe_reference reference;
38 /* fence holds a weak reference to the batch until the batch is flushed,
39 * at which point fd_fence_populate() is called and timestamp and possibly
40 * fence_fd become valid and the week reference is dropped.
41 */
42 struct fd_batch *batch;
43 struct fd_pipe *pipe;
44 struct fd_screen *screen;
45 int fence_fd;
46 uint32_t timestamp;
47 };
48
49 static void fence_flush(struct pipe_fence_handle *fence)
50 {
51 if (fence->batch)
52 fd_batch_flush(fence->batch);
53 debug_assert(!fence->batch);
54 }
55
56 void fd_fence_populate(struct pipe_fence_handle *fence,
57 uint32_t timestamp, int fence_fd)
58 {
59 if (!fence->batch)
60 return;
61 fence->timestamp = timestamp;
62 fence->fence_fd = fence_fd;
63 fence->batch = NULL;
64 }
65
66 static void fd_fence_destroy(struct pipe_fence_handle *fence)
67 {
68 if (fence->fence_fd != -1)
69 close(fence->fence_fd);
70 fd_pipe_del(fence->pipe);
71 FREE(fence);
72 }
73
74 void fd_fence_ref(struct pipe_fence_handle **ptr,
75 struct pipe_fence_handle *pfence)
76 {
77 if (pipe_reference(&(*ptr)->reference, &pfence->reference))
78 fd_fence_destroy(*ptr);
79
80 *ptr = pfence;
81 }
82
83 bool fd_fence_finish(struct pipe_screen *pscreen,
84 struct pipe_context *ctx,
85 struct pipe_fence_handle *fence,
86 uint64_t timeout)
87 {
88 fence_flush(fence);
89
90 if (fence->fence_fd != -1) {
91 int ret = sync_wait(fence->fence_fd, timeout / 1000000);
92 return ret == 0;
93 }
94
95 if (fd_pipe_wait_timeout(fence->pipe, fence->timestamp, timeout))
96 return false;
97
98 return true;
99 }
100
101 static struct pipe_fence_handle * fence_create(struct fd_context *ctx,
102 struct fd_batch *batch, uint32_t timestamp, int fence_fd)
103 {
104 struct pipe_fence_handle *fence;
105
106 fence = CALLOC_STRUCT(pipe_fence_handle);
107 if (!fence)
108 return NULL;
109
110 pipe_reference_init(&fence->reference, 1);
111
112 fence->batch = batch;
113 fence->pipe = fd_pipe_ref(ctx->pipe);
114 fence->screen = ctx->screen;
115 fence->timestamp = timestamp;
116 fence->fence_fd = fence_fd;
117
118 return fence;
119 }
120
121 void fd_create_fence_fd(struct pipe_context *pctx,
122 struct pipe_fence_handle **pfence, int fd,
123 enum pipe_fd_type type)
124 {
125 assert(type == PIPE_FD_TYPE_NATIVE_SYNC);
126 *pfence = fence_create(fd_context(pctx), NULL, 0, os_dupfd_cloexec(fd));
127 }
128
129 void fd_fence_server_sync(struct pipe_context *pctx,
130 struct pipe_fence_handle *fence)
131 {
132 struct fd_context *ctx = fd_context(pctx);
133 struct fd_batch *batch = fd_context_batch(ctx);
134
135 fence_flush(fence);
136
137 /* if not an external fence, then nothing more to do without preemption: */
138 if (fence->fence_fd == -1)
139 return;
140
141 if (sync_accumulate("freedreno", &batch->in_fence_fd, fence->fence_fd)) {
142 /* error */
143 }
144 }
145
146 int fd_fence_get_fd(struct pipe_screen *pscreen,
147 struct pipe_fence_handle *fence)
148 {
149 fence_flush(fence);
150 return os_dupfd_cloexec(fence->fence_fd);
151 }
152
153 struct pipe_fence_handle * fd_fence_create(struct fd_batch *batch)
154 {
155 return fence_create(batch->ctx, batch, 0, -1);
156 }