DonnaTaskHelperRc donna_task_helper (DonnaTask *task, task_helper_ui show_ui, task_helper_ui destroy_ui, gpointer data) { DonnaTaskHelper th; fd_set fds; gint fd_task; g_return_val_if_fail (DONNA_IS_TASK (task), DONNA_TASK_HELPER_RC_ERROR); g_return_val_if_fail (show_ui != NULL, DONNA_TASK_HELPER_RC_ERROR); g_return_val_if_fail (destroy_ui != NULL, DONNA_TASK_HELPER_RC_ERROR); /* create our eventfd */ th.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK); if (th.fd == -1) return DONNA_TASK_HELPER_RC_ERROR; /* init th */ g_mutex_init (&th.mutex); th.has_destroy = 0; th.show_ui = show_ui; th.destroy_ui = destroy_ui; th.data = data; th.rc = DONNA_TASK_HELPER_RC_SUCCESS; /* get the task-s fd, in case it gets paused/cancelled */ fd_task = donna_task_get_fd (task); g_idle_add ((GSourceFunc) do_show_ui, &th); for (;;) { gint ret; FD_ZERO (&fds); FD_SET (th.fd, &fds); if (fd_task >= 0) FD_SET (fd_task, &fds); /* block thread until user "answered" (helper_done() was called, * unblocking our fd) or the task gets paused/cancelled */ ret = select (MAX (th.fd, fd_task) + 1, &fds, NULL, NULL, 0); if (ret < 0) { gint _errno = errno; if (errno == EINTR) continue; g_warning ("TaskHelper: Call to select() failed: %s", g_strerror (_errno)); continue; } g_mutex_lock (&th.mutex); /* normal ending, i.e. user did "answer" -- meaning the UI was * destroyed, nothing more to do but free stuff & return */ if (FD_ISSET (th.fd, &fds)) { g_mutex_unlock (&th.mutex); break; } /* task was paused/cancelled */ if (FD_ISSET (fd_task, &fds)) { th.rc = DONNA_TASK_HELPER_RC_CANCELLING; /* flag that there is (will be) a pending call to destroy_ui. This * is used to handle race condition where the user answers while * we're doing this */ th.has_destroy = 1; /* disable this for now */ fd_task = -1; /* install the call to destroy the ui */ g_idle_add ((GSourceFunc) do_destroy_ui, &th); /* and block again on our fd (waiting for UI to be destroyed) */ } g_mutex_unlock (&th.mutex); } close (th.fd); g_mutex_clear (&th.mutex); return th.rc; }
static void run_shm_transmitter_test (gint flags) { GError *error = NULL; FsTransmitter *trans; FsStreamTransmitter *st; GstBus *bus = NULL; GParameter params[1]; GList *local_cands = NULL; GstStateChangeReturn ret; FsCandidate *cand; GList *remote_cands = NULL; int param_count = 0; done = FALSE; connected_count = 0; g_cond_init (&cond); g_mutex_init (&test_mutex); buffer_count[0] = 0; buffer_count[1] = 0; received_known[0] = 0; received_known[1] = 0; got_candidates[0] = FALSE; got_candidates[1] = FALSE; got_prepared[0] = FALSE; got_prepared[1] = FALSE; if (unlink ("/tmp/src1") < 0 && errno != ENOENT) fail ("Could not unlink /tmp/src1: %s", strerror (errno)); if (unlink ("/tmp/src2") < 0 && errno != ENOENT) fail ("Could not unlink /tmp/src2: %s", strerror (errno)); local_cands = g_list_append (local_cands, fs_candidate_new (NULL, 1, FS_CANDIDATE_TYPE_HOST, FS_NETWORK_PROTOCOL_UDP, "/tmp/src1", 0)); local_cands = g_list_append (local_cands, fs_candidate_new (NULL, 2, FS_CANDIDATE_TYPE_HOST, FS_NETWORK_PROTOCOL_UDP, "/tmp/src2", 0)); if (flags & FLAG_LOCAL_CANDIDATES) { memset (params, 0, sizeof (GParameter)); params[0].name = "preferred-local-candidates"; g_value_init (¶ms[0].value, FS_TYPE_CANDIDATE_LIST); g_value_take_boxed (¶ms[0].value, local_cands); param_count = 1; } associate_on_source = !(flags & FLAG_NO_SOURCE); if ((flags & FLAG_NOT_SENDING) && (flags & FLAG_RECVONLY_FILTER)) { buffer_count[0] = 20; received_known[0] = 20; } trans = fs_transmitter_new ("shm", 2, 0, &error); if (error) ts_fail ("Error creating transmitter: (%s:%d) %s", g_quark_to_string (error->domain), error->code, error->message); ts_fail_if (trans == NULL, "No transmitter create, yet error is still NULL"); g_clear_error (&error); if (flags & FLAG_RECVONLY_FILTER) ts_fail_unless (g_signal_connect (trans, "get-recvonly-filter", G_CALLBACK (get_recvonly_filter), NULL)); pipeline = setup_pipeline (trans, G_CALLBACK (_handoff_handler)); bus = gst_element_get_bus (pipeline); gst_bus_add_watch (bus, bus_error_callback, NULL); gst_bus_enable_sync_message_emission (bus); g_signal_connect (bus, "sync-message::error", G_CALLBACK (sync_error_handler), NULL); gst_object_unref (bus); st = fs_transmitter_new_stream_transmitter (trans, NULL, param_count, params, &error); if (param_count) g_value_unset (¶ms[0].value); if (error) ts_fail ("Error creating stream transmitter: (%s:%d) %s", g_quark_to_string (error->domain), error->code, error->message); ts_fail_if (st == NULL, "No stream transmitter created, yet error is NULL"); g_clear_error (&error); g_object_set (st, "sending", !(flags & FLAG_NOT_SENDING), NULL); ts_fail_unless (g_signal_connect (st, "new-local-candidate", G_CALLBACK (_new_local_candidate), trans), "Could not connect new-local-candidate signal"); ts_fail_unless (g_signal_connect (st, "local-candidates-prepared", G_CALLBACK (_candidate_prepared), NULL), "Could not connect local-candidates-prepared signal"); ts_fail_unless (g_signal_connect (st, "error", G_CALLBACK (stream_transmitter_error), NULL), "Could not connect error signal"); ts_fail_unless (g_signal_connect (st, "known-source-packet-received", G_CALLBACK (_known_source_packet_received), NULL), "Could not connect known-source-packet-received signal"); ts_fail_unless (g_signal_connect (st, "state-changed", G_CALLBACK (_state_changed), NULL), "Could not connect state-changed signal"); if (!fs_stream_transmitter_gather_local_candidates (st, &error)) { if (error) ts_fail ("Could not start gathering local candidates (%s:%d) %s", g_quark_to_string (error->domain), error->code, error->message); else ts_fail ("Could not start gathering candidates" " (without a specified error)"); } else { ts_fail_unless (error == NULL); } g_clear_error (&error); ret = gst_element_set_state (pipeline, GST_STATE_PLAYING); ts_fail_if (ret == GST_STATE_CHANGE_FAILURE, "Could not set the pipeline to playing"); if (!(flags & FLAG_LOCAL_CANDIDATES)) { ret = fs_stream_transmitter_force_remote_candidates (st, local_cands, &error); fs_candidate_list_destroy (local_cands); if (error) ts_fail ("Error while adding candidate: (%s:%d) %s", g_quark_to_string (error->domain), error->code, error->message); ts_fail_unless (ret == TRUE, "No detailed error from add_remote_candidate"); } else { ts_fail_unless (error == NULL); } g_clear_error (&error); cand = fs_candidate_new (NULL, 1, FS_CANDIDATE_TYPE_HOST, FS_NETWORK_PROTOCOL_UDP, NULL, 0); cand->username = g_strdup ("/tmp/src1"); remote_cands = g_list_prepend (remote_cands, cand); cand = fs_candidate_new (NULL, 2, FS_CANDIDATE_TYPE_HOST, FS_NETWORK_PROTOCOL_UDP, NULL, 0); cand->username = g_strdup ("/tmp/src2"); remote_cands = g_list_prepend (remote_cands, cand); ret = fs_stream_transmitter_force_remote_candidates (st, remote_cands, &error); fs_candidate_list_destroy (remote_cands); if (error) ts_fail ("Error while adding candidate: (%s:%d) %s", g_quark_to_string (error->domain), error->code, error->message); ts_fail_unless (ret == TRUE, "No detailed error from add_remote_candidate"); g_clear_error (&error); g_mutex_lock (&test_mutex); while (connected_count < 2) g_cond_wait (&cond, &test_mutex); g_mutex_unlock (&test_mutex); setup_fakesrc (trans, pipeline, 1); setup_fakesrc (trans, pipeline, 2); g_mutex_lock (&test_mutex); while (!done) g_cond_wait (&cond, &test_mutex); g_mutex_unlock (&test_mutex); fail_unless (got_prepared[0] == TRUE); fail_unless (got_prepared[1] == TRUE); fail_unless (got_candidates[0] == TRUE); fail_unless (got_candidates[1] == TRUE); gst_element_set_state (pipeline, GST_STATE_NULL); if (st) { fs_stream_transmitter_stop (st); g_object_unref (st); } g_object_unref (trans); gst_object_unref (pipeline); g_cond_clear (&cond); g_mutex_clear (&test_mutex); }
extern void FreeMutex(Mutex mutex) { g_mutex_clear(&mutex); }
static void sync_data_clear (SyncData *data) { g_mutex_clear (&data->mutex); g_cond_clear (&data->cond); }