@@ -232,39 +232,62 @@ void sync_fence_install(struct sync_fence *fence, int fd)
}
EXPORT_SYMBOL(sync_fence_install);
+static void sync_fence_add_pt(struct sync_fence *fence, int *i, struct fence *pt) {
+ fence->cbs[*i].sync_pt = pt;
+ fence->cbs[*i].fence = fence;
+
+ if (!fence_add_callback(pt, &fence->cbs[*i].cb, fence_check_cb_func)) {
+ fence_get(pt);
+ (*i)++;
+ }
+}
+
struct sync_fence *sync_fence_merge(const char *name,
struct sync_fence *a, struct sync_fence *b)
{
int num_fences = a->num_fences + b->num_fences;
struct sync_fence *fence;
- int i;
+ int i, i_a, i_b;
fence = sync_fence_alloc(offsetof(struct sync_fence, cbs[num_fences]), name);
if (fence == NULL)
return NULL;
- fence->num_fences = num_fences;
atomic_set(&fence->status, num_fences);
- for (i = 0; i < a->num_fences; ++i) {
- struct fence *pt = a->cbs[i].sync_pt;
-
- fence_get(pt);
- fence->cbs[i].sync_pt = pt;
- fence->cbs[i].fence = fence;
- if (fence_add_callback(pt, &fence->cbs[i].cb, fence_check_cb_func))
- atomic_dec(&fence->status);
+ /*
+ * Assume sync_fence a and b are both ordered and have no
+ * duplicates with the same context.
+ *
+ * If a sync_fence can only be created with sync_fence_merge
+ * and sync_fence_create, this is a reasonable assumption.
+ */
+ for (i = i_a = i_b = 0; i_a < a->num_fences || i_b < b->num_fences; ) {
+ struct fence *pt_a = i_a < a->num_fences ? a->cbs[i_a].sync_pt : NULL;
+ struct fence *pt_b = i_b < b->num_fences ? b->cbs[i_b].sync_pt : NULL;
+
+ if (!pt_b || pt_a->context < pt_b->context) {
+ sync_fence_add_pt(fence, &i, pt_a);
+
+ i_a++;
+ } else if (!pt_a || pt_a->context > pt_b->context) {
+ sync_fence_add_pt(fence, &i, pt_b);
+
+ i_b++;
+ } else {
+ if (pt_a->seqno - pt_b->seqno <= INT_MAX)
+ sync_fence_add_pt(fence, &i, pt_a);
+ else
+ sync_fence_add_pt(fence, &i, pt_b);
+
+ i_a++;
+ i_b++;
+ }
}
- for (i = 0; i < b->num_fences; ++i) {
- struct fence *pt = b->cbs[i].sync_pt;
-
- fence_get(pt);
- fence->cbs[a->num_fences + i].sync_pt = pt;
- fence->cbs[a->num_fences + i].fence = fence;
- if (fence_add_callback(pt, &fence->cbs[a->num_fences + i].cb, fence_check_cb_func))
- atomic_dec(&fence->status);
- }
+ if (num_fences > i)
+ atomic_sub(num_fences - i, &fence->status);
+ fence->num_fences = i;
sync_fence_debug_add(fence);
return fence;