// Must NOT be called from the main thread. // Adds a list of tracks to the *top* of the play queue // Blocks until the task has finished, since the urls pointer may become invalid during execution otherwise. void add_tracks_to_queue_top(struct url *urls, uint32_t count) { HANDLE hFinished = CreateEvent(NULL, TRUE, FALSE, NULL); // First, fetch the current queue contents; this must happen in the main thread. pfc::list_t<t_playback_queue_item> queueContents; in_main_thread([&] { static_api_ptr_t<playlist_manager>()->queue_get_contents(queueContents); SetEvent(hFinished); }); WaitForSingleObject(hFinished, INFINITE); // Next, add our tracks to the top of the queue; this must NOT happen in the main thread. if (queueContents.get_count() == 0) { enqueue_tracks(urls, count); return; } else replace_queue_with_tracks(urls, count); // Finally, add back the tracks that were in the queue to begin with; this must happen in the main thread. ResetEvent(hFinished); in_main_thread([&] { for (t_size i = 0; i < queueContents.get_count(); i++) { static_api_ptr_t<playlist_manager>()->queue_add_item(queueContents.get_item(i).m_handle); } SetEvent(hFinished); }); WaitForSingleObject(hFinished, INFINITE); }
// Starts playback on the queued tracks. void start_playing_queue() { in_main_thread([] { auto p_control = static_api_ptr_t<playback_control>(); if (p_control->is_playing() || p_control->is_paused()) p_control->next(); else p_control->play_or_unpause(); }); }
// Must NOT be called from the main thread. // Replaces the play queue with the list of tracks // Blocks until the task has finished, since the urls pointer may become invalid during execution otherwise. void replace_queue_with_tracks(struct url *urls, uint32_t count) { HANDLE hFinished = CreateEvent(NULL, TRUE, FALSE, NULL); in_main_thread([=] { static_api_ptr_t<playlist_manager>()->queue_flush(); SetEvent(hFinished); }); WaitForSingleObject(hFinished, INFINITE); enqueue_tracks(urls, count); }
// Must NOT be called from the main thread. // Adds a list of tracks to the *end* of the play queue. // Blocks until the task has finished, since the urls pointer may become invalid during execution otherwise. void enqueue_tracks(struct url *urls, uint32_t count) { HANDLE hFinished = CreateEvent(NULL, TRUE, FALSE, NULL); metadb_handle_list tracks = get_handles_from_urls(urls, count); in_main_thread([=] { for (size_t i = 0; i < tracks.get_count(); i++) { static_api_ptr_t<playlist_manager>()->queue_add_item(tracks.get_item(i)); } SetEvent(hFinished); }); WaitForSingleObject(hFinished, INFINITE); }
/** Helper function for threading unit tests: This function runs in a * subthread. It grabs its own mutex (start1 or start2) to make sure that it * should start, then it repeatedly alters _test_thread_strmap protected by * thread_test_mutex_. */ static void thread_test_func_(void* _s) { char *s = _s; int i, *count; tor_mutex_t *m; char buf[64]; char **cp; if (!strcmp(s, "thread 1")) { m = thread_test_start1_; cp = &thread1_name_; count = &t1_count; thread_fn_tid1 = tor_get_thread_id(); } else { m = thread_test_start2_; cp = &thread2_name_; count = &t2_count; thread_fn_tid2 = tor_get_thread_id(); } tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id()); *cp = tor_strdup(buf); tor_mutex_acquire(m); for (i=0; i<10000; ++i) { tor_mutex_acquire(thread_test_mutex_); strmap_set(thread_test_strmap_, "last to run", *cp); ++*count; tor_mutex_release(thread_test_mutex_); } tor_mutex_acquire(thread_test_mutex_); strmap_set(thread_test_strmap_, s, *cp); if (in_main_thread()) ++thread_fns_failed; tor_mutex_release(thread_test_mutex_); tor_mutex_release(m); spawn_exit(); }