sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1, const sp<Fence>& f2) { ATRACE_CALL(); int result; // Merge the two fences. In the case where one of the fences is not a // valid fence (e.g. NO_FENCE) we merge the one valid fence with itself so // that a new fence with the given name is created. if (f1->isValid() && f2->isValid()) { result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd); } else if (f1->isValid()) { result = sync_merge(name.string(), f1->mFenceFd, f1->mFenceFd); } else if (f2->isValid()) { result = sync_merge(name.string(), f2->mFenceFd, f2->mFenceFd); } else { return NO_FENCE; } if (result == -1) { status_t err = -errno; ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)", name.string(), f1->mFenceFd, f2->mFenceFd, strerror(-err), err); return NO_FENCE; } return sp<Fence>(new Fence(result)); }
int test_fence_multi_timeline_wait(void) { int timelineA, timelineB, timelineC; int fenceA, fenceB, fenceC, merged; int valid, active, signaled, ret; timelineA = sw_sync_timeline_create(); timelineB = sw_sync_timeline_create(); timelineC = sw_sync_timeline_create(); fenceA = sw_sync_fence_create(timelineA, "fenceA", 5); fenceB = sw_sync_fence_create(timelineB, "fenceB", 5); fenceC = sw_sync_fence_create(timelineC, "fenceC", 5); merged = sync_merge("mergeFence", fenceB, fenceA); merged = sync_merge("mergeFence", fenceC, merged); valid = sw_sync_fence_is_valid(merged); ASSERT(valid, "Failure merging fence from various timelines\n"); /* Confirm fence isn't signaled */ active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); ASSERT(active == 3, "Fence signaled too early!\n"); ret = sync_wait(merged, 0); ASSERT(ret == 0, "Failure waiting on fence until timeout\n"); ret = sw_sync_timeline_inc(timelineA, 5); active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED); ASSERT(active == 2 && signaled == 1, "Fence did not signal properly!\n"); ret = sw_sync_timeline_inc(timelineB, 5); active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED); ASSERT(active == 1 && signaled == 2, "Fence did not signal properly!\n"); ret = sw_sync_timeline_inc(timelineC, 5); active = sync_fence_count_with_status(merged, FENCE_STATUS_ACTIVE); signaled = sync_fence_count_with_status(merged, FENCE_STATUS_SIGNALED); ASSERT(active == 0 && signaled == 3, "Fence did not signal properly!\n"); /* confirm you can successfully wait */ ret = sync_wait(merged, 100); ASSERT(ret > 0, "Failure waiting on signaled fence\n"); sw_sync_fence_destroy(merged); sw_sync_fence_destroy(fenceC); sw_sync_fence_destroy(fenceB); sw_sync_fence_destroy(fenceA); sw_sync_timeline_destroy(timelineC); sw_sync_timeline_destroy(timelineB); sw_sync_timeline_destroy(timelineA); return 0; }
sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1, const sp<Fence>& f2) { ATRACE_CALL(); int result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd); if (result == -1) { status_t err = -errno; ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)", name.string(), f1->mFenceFd, f2->mFenceFd, strerror(-err), err); return NO_FENCE; } return sp<Fence>(new Fence(result)); }
static int mpcs_consumer_thread(void) { int fence, merged, tmp, valid, it, i; int *producer_timelines = test_data_mpsc.producer_timelines; int consumer_timeline = test_data_mpsc.consumer_timeline; int iterations = test_data_mpsc.iterations; int n = test_data_mpsc.threads; for (it = 1; it <= iterations; it++) { fence = sw_sync_fence_create(producer_timelines[0], "name", it); for (i = 1; i < n; i++) { tmp = sw_sync_fence_create(producer_timelines[i], "name", it); merged = sync_merge("name", tmp, fence); sw_sync_fence_destroy(tmp); sw_sync_fence_destroy(fence); fence = merged; } valid = sw_sync_fence_is_valid(fence); ASSERT(valid, "Failure merging fences\n"); /* * Make sure we see an increment from every producer thread. * Vary the means by which we wait. */ if (iterations % 8 != 0) { ASSERT(sync_wait(fence, -1) > 0, "Producers did not increment as expected\n"); } else { ASSERT(busy_wait_on_fence(fence) == 0, "Producers did not increment as expected\n"); } ASSERT(test_data_mpsc.counter == n * it, "Counter value mismatch!\n"); /* Release the producer threads */ ASSERT(sw_sync_timeline_inc(consumer_timeline, 1) == 0, "Failure releasing producer threads\n"); sw_sync_fence_destroy(fence); } return 0; }
void FenceHandle::Merge(const FenceHandle& aFenceHandle) { #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 if (!aFenceHandle.IsValid()) { return; } if (!IsValid()) { mFence = aFenceHandle.mFence; } else { int result = sync_merge("FenceHandle", mFence->mFd, aFenceHandle.mFence->mFd); if (result == -1) { mFence = aFenceHandle.mFence; } else { mFence = new FdObj(result); } } #endif }
static void test_sync_file_fences(struct pipe_context *ctx) { struct pipe_screen *screen = ctx->screen; bool pass = true; enum pipe_fd_type fd_type = PIPE_FD_TYPE_NATIVE_SYNC; if (!screen->get_param(screen, PIPE_CAP_NATIVE_FENCE_FD)) return; struct cso_context *cso = cso_create_context(ctx, 0); struct pipe_resource *buf = pipe_buffer_create(screen, 0, PIPE_USAGE_DEFAULT, 1024 * 1024); struct pipe_resource *tex = util_create_texture2d(screen, 4096, 1024, PIPE_FORMAT_R8_UNORM, 0); struct pipe_fence_handle *buf_fence = NULL, *tex_fence = NULL; /* Run 2 clears, get fencess. */ uint32_t value = 0; ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value)); ctx->flush(ctx, &buf_fence, PIPE_FLUSH_FENCE_FD); struct pipe_box box; u_box_2d(0, 0, tex->width0, tex->height0, &box); ctx->clear_texture(ctx, tex, 0, &box, &value); ctx->flush(ctx, &tex_fence, PIPE_FLUSH_FENCE_FD); pass = pass && buf_fence && tex_fence; /* Export fences. */ int buf_fd = screen->fence_get_fd(screen, buf_fence); int tex_fd = screen->fence_get_fd(screen, tex_fence); pass = pass && buf_fd >= 0 && tex_fd >= 0; /* Merge fences. */ int merged_fd = sync_merge("test", buf_fd, tex_fd); pass = pass && merged_fd >= 0; /* (Re)import all fences. */ struct pipe_fence_handle *re_buf_fence = NULL, *re_tex_fence = NULL; struct pipe_fence_handle *merged_fence = NULL; ctx->create_fence_fd(ctx, &re_buf_fence, buf_fd, fd_type); ctx->create_fence_fd(ctx, &re_tex_fence, tex_fd, fd_type); ctx->create_fence_fd(ctx, &merged_fence, merged_fd, fd_type); pass = pass && re_buf_fence && re_tex_fence && merged_fence; /* Run another clear after waiting for everything. */ struct pipe_fence_handle *final_fence = NULL; ctx->fence_server_sync(ctx, merged_fence); value = 0xff; ctx->clear_buffer(ctx, buf, 0, buf->width0, &value, sizeof(value)); ctx->flush(ctx, &final_fence, PIPE_FLUSH_FENCE_FD); pass = pass && final_fence; /* Wait for the last fence. */ int final_fd = screen->fence_get_fd(screen, final_fence); pass = pass && final_fd >= 0; pass = pass && sync_wait(final_fd, -1) == 0; /* Check that all fences are signalled. */ pass = pass && sync_wait(buf_fd, 0) == 0; pass = pass && sync_wait(tex_fd, 0) == 0; pass = pass && sync_wait(merged_fd, 0) == 0; pass = pass && screen->fence_finish(screen, NULL, buf_fence, 0); pass = pass && screen->fence_finish(screen, NULL, tex_fence, 0); pass = pass && screen->fence_finish(screen, NULL, re_buf_fence, 0); pass = pass && screen->fence_finish(screen, NULL, re_tex_fence, 0); pass = pass && screen->fence_finish(screen, NULL, merged_fence, 0); pass = pass && screen->fence_finish(screen, NULL, final_fence, 0); /* Cleanup. */ #ifndef PIPE_OS_WINDOWS if (buf_fd >= 0) close(buf_fd); if (tex_fd >= 0) close(tex_fd); if (merged_fd >= 0) close(merged_fd); if (final_fd >= 0) close(final_fd); #endif screen->fence_reference(screen, &buf_fence, NULL); screen->fence_reference(screen, &tex_fence, NULL); screen->fence_reference(screen, &re_buf_fence, NULL); screen->fence_reference(screen, &re_tex_fence, NULL); screen->fence_reference(screen, &merged_fence, NULL); screen->fence_reference(screen, &final_fence, NULL); cso_destroy_context(cso); pipe_resource_reference(&buf, NULL); pipe_resource_reference(&tex, NULL); util_report_result(pass); }