summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2023-01-21 17:48:11 +0000
committerAidan MacDonald <amachronic@protonmail.com>2023-01-23 12:24:12 +0000
commit65b3ff81c5fba2e72aa21c7c80dc7133b51e042b (patch)
tree7be4749f8ffa087d5e7393c8ba106ea4bf49cccf
parentce52d0c870f715ee979a1bf5e51857c200543d9d (diff)
downloadrockbox-65b3ff81c5fba2e72aa21c7c80dc7133b51e042b.tar.gz
rockbox-65b3ff81c5fba2e72aa21c7c80dc7133b51e042b.zip
playlist: Fix dircache scan thread deadlocks
Fix deadlocks in the dircache scan thread caused by incorrect lock ordering. Mutating operations need to stop the thread to prevent it from accessing invalid data; this must always be done before taking the playlist lock to avoid deadlocking the scan thread. Change-Id: If719a8b28ed0b0b3eac068073581e606c4a5f58a
-rw-r--r--apps/playlist.c467
1 files changed, 246 insertions, 221 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 7b7b91c22f..bf65bb8656 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -67,6 +67,7 @@
67 flushed to disk when required. 67 flushed to disk when required.
68 */ 68 */
69 69
70//#define LOGF_ENABLE
70#include <stdio.h> 71#include <stdio.h>
71#include <stdlib.h> 72#include <stdlib.h>
72#include <ctype.h> 73#include <ctype.h>
@@ -106,11 +107,9 @@
106#ifdef HAVE_DIRCACHE 107#ifdef HAVE_DIRCACHE
107#include "dircache.h" 108#include "dircache.h"
108#endif 109#endif
110#include "logf.h"
109 111
110#if 0//def ROCKBOX_HAS_LOGDISKF 112#if 0//def ROCKBOX_HAS_LOGDISKF
111#warning LOGF enabled
112#define LOGF_ENABLE
113#include "logf.h"
114#undef DEBUGF 113#undef DEBUGF
115#undef ERRORF 114#undef ERRORF
116#undef WARNF 115#undef WARNF
@@ -119,9 +118,6 @@
119#define ERRORF DEBUGF 118#define ERRORF DEBUGF
120#define WARNF DEBUGF 119#define WARNF DEBUGF
121#define NOTEF DEBUGF 120#define NOTEF DEBUGF
122//ERRORF
123//WARNF
124//NOTEF
125#endif 121#endif
126 122
127/* default load buffer size (should be at least 1 KiB) */ 123/* default load buffer size (should be at least 1 KiB) */
@@ -190,12 +186,11 @@ static void dc_init_filerefs(struct playlist_info *playlist,
190} 186}
191 187
192#ifdef HAVE_DIRCACHE 188#ifdef HAVE_DIRCACHE
193#define PLAYLIST_LOAD_POINTERS 1 189#define PLAYLIST_DC_SCAN_START 1
194#define PLAYLIST_CLEAN_POINTERS 2 190#define PLAYLIST_DC_SCAN_STOP 2
195static bool dc_has_dirty_pointers = false;
196 191
197static struct event_queue playlist_queue SHAREDBSS_ATTR; 192static struct event_queue playlist_queue;
198static struct queue_sender_list playlist_queue_sender_list SHAREDBSS_ATTR; 193static struct queue_sender_list playlist_queue_sender_list;
199static long playlist_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)]; 194static long playlist_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)];
200static const char dc_thread_playlist_name[] = "playlist cachectrl"; 195static const char dc_thread_playlist_name[] = "playlist cachectrl";
201#endif 196#endif
@@ -232,22 +227,20 @@ static void notify_buffer_full(void)
232 splash(HZ*2, ID2P(LANG_PLAYLIST_BUFFER_FULL)); 227 splash(HZ*2, ID2P(LANG_PLAYLIST_BUFFER_FULL));
233} 228}
234 229
235static void dc_load_playlist_pointers(void) 230static void dc_thread_start(struct playlist_info *playlist, bool is_dirty)
236{ 231{
237#ifdef HAVE_DIRCACHE 232#ifdef HAVE_DIRCACHE
238 queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); 233 if (playlist == &current_playlist)
234 queue_post(&playlist_queue, PLAYLIST_DC_SCAN_START, is_dirty);
239#endif 235#endif
240/* No-Op for non dircache targets */
241} 236}
242 237
243static void dc_discard_playlist_pointers(void) 238static void dc_thread_stop(struct playlist_info *playlist)
244{ 239{
245#ifdef HAVE_DIRCACHE 240#ifdef HAVE_DIRCACHE
246 /* dump any pointers currently waiting */ 241 if (playlist == &current_playlist)
247 if (dc_has_dirty_pointers) 242 queue_send(&playlist_queue, PLAYLIST_DC_SCAN_STOP, 0);
248 queue_send(&playlist_queue, PLAYLIST_CLEAN_POINTERS, 0);
249#endif 243#endif
250/* No-Op for non dircache targets */
251} 244}
252 245
253static void close_playlist_control_file(struct playlist_info *playlist) 246static void close_playlist_control_file(struct playlist_info *playlist)
@@ -547,8 +540,6 @@ static void update_playlist_filename_unlocked(struct playlist_info* playlist,
547 */ 540 */
548static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume) 541static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume)
549{ 542{
550 dc_discard_playlist_pointers();
551
552 if(playlist->fd >= 0) /* If there is an already open playlist, close it. */ 543 if(playlist->fd >= 0) /* If there is an already open playlist, close it. */
553 { 544 {
554 close(playlist->fd); 545 close(playlist->fd);
@@ -1556,8 +1547,8 @@ static int directory_search_callback(char* filename, void* context)
1556/* 1547/*
1557 * remove track at specified position 1548 * remove track at specified position
1558 */ 1549 */
1559static int remove_track_from_playlist(struct playlist_info* playlist, 1550static int remove_track_unlocked(struct playlist_info* playlist,
1560 int position, bool write) 1551 int position, bool write)
1561{ 1552{
1562 int i; 1553 int i;
1563 int result = 0; 1554 int result = 0;
@@ -1566,8 +1557,6 @@ static int remove_track_from_playlist(struct playlist_info* playlist,
1566 if (playlist->amount <= 0) 1557 if (playlist->amount <= 0)
1567 return -1; 1558 return -1;
1568 1559
1569 playlist_mutex_lock(&(playlist->mutex));
1570
1571 inserted = playlist->indices[position] & PLAYLIST_INSERT_TYPE_MASK; 1560 inserted = playlist->indices[position] & PLAYLIST_INSERT_TYPE_MASK;
1572 1561
1573#ifdef HAVE_DIRCACHE 1562#ifdef HAVE_DIRCACHE
@@ -1613,7 +1602,6 @@ static int remove_track_from_playlist(struct playlist_info* playlist,
1613 sync_control(playlist, false); 1602 sync_control(playlist, false);
1614 } 1603 }
1615 1604
1616 playlist_mutex_unlock(&(playlist->mutex));
1617 return result; 1605 return result;
1618} 1606}
1619 1607
@@ -1642,18 +1630,14 @@ static void find_and_set_playlist_index_unlocked(struct playlist_info* playlist,
1642 * randomly rearrange the array of indices for the playlist. If start_current 1630 * randomly rearrange the array of indices for the playlist. If start_current
1643 * is true then update the index to the new index of the current playing track 1631 * is true then update the index to the new index of the current playing track
1644 */ 1632 */
1645static int randomise_playlist(struct playlist_info* playlist, 1633static int randomise_playlist_unlocked(struct playlist_info* playlist,
1646 unsigned int seed, bool start_current, 1634 unsigned int seed, bool start_current,
1647 bool write) 1635 bool write)
1648{ 1636{
1649 int count; 1637 int count;
1650 int candidate; 1638 int candidate;
1651 unsigned int current = playlist->indices[playlist->index]; 1639 unsigned int current = playlist->indices[playlist->index];
1652 1640
1653 playlist_mutex_lock(&(playlist->mutex));
1654
1655 dc_discard_playlist_pointers();
1656
1657 /* seed 0 is used to identify sorted playlist for resume purposes */ 1641 /* seed 0 is used to identify sorted playlist for resume purposes */
1658 if (seed == 0) 1642 if (seed == 0)
1659 seed = 1; 1643 seed = 1;
@@ -1698,8 +1682,6 @@ static int randomise_playlist(struct playlist_info* playlist,
1698 playlist->first_index, NULL, NULL, NULL); 1682 playlist->first_index, NULL, NULL, NULL);
1699 } 1683 }
1700 1684
1701 playlist_mutex_unlock(&(playlist->mutex));
1702
1703 return 0; 1685 return 0;
1704} 1686}
1705 1687
@@ -1740,8 +1722,6 @@ static int sort_playlist_unlocked(struct playlist_info* playlist,
1740{ 1722{
1741 unsigned int current = playlist->indices[playlist->index]; 1723 unsigned int current = playlist->indices[playlist->index];
1742 1724
1743 dc_discard_playlist_pointers();
1744
1745 if (playlist->amount > 0) 1725 if (playlist->amount > 0)
1746 qsort((void*)playlist->indices, playlist->amount, 1726 qsort((void*)playlist->indices, playlist->amount,
1747 sizeof(playlist->indices[0]), sort_compare_fn); 1727 sizeof(playlist->indices[0]), sort_compare_fn);
@@ -1751,7 +1731,6 @@ static int sort_playlist_unlocked(struct playlist_info* playlist,
1751 * sort two arrays at once :/ 1731 * sort two arrays at once :/
1752 * FIXME: Please implement a better way to do this. */ 1732 * FIXME: Please implement a better way to do this. */
1753 dc_init_filerefs(playlist, 0, playlist->max_playlist_size); 1733 dc_init_filerefs(playlist, 0, playlist->max_playlist_size);
1754 dc_load_playlist_pointers();
1755#endif 1734#endif
1756 1735
1757 if (start_current) 1736 if (start_current)
@@ -1917,55 +1896,81 @@ static void dc_thread_playlist(void)
1917 int seek; 1896 int seek;
1918 bool control_file; 1897 bool control_file;
1919 1898
1920 int sleep_time = 5; 1899 /* Thread starts out stopped */
1921 1900 long sleep_time = TIMEOUT_BLOCK;
1922#ifdef HAVE_DISK_STORAGE 1901 int stop_count = 1;
1923 if (global_settings.disk_spindown > 1 && 1902 bool is_dirty = false;
1924 global_settings.disk_spindown <= 5)
1925 sleep_time = global_settings.disk_spindown - 1;
1926#endif
1927 1903
1928 while (1) 1904 while (1)
1929 { 1905 {
1930 queue_wait_w_tmo(&playlist_queue, &ev, HZ*sleep_time); 1906 queue_wait_w_tmo(&playlist_queue, &ev, sleep_time);
1931 1907
1932 switch (ev.id) 1908 switch (ev.id)
1933 { 1909 {
1934 case PLAYLIST_CLEAN_POINTERS: 1910 case PLAYLIST_DC_SCAN_START:
1935 dc_has_dirty_pointers = false; 1911 if (ev.data)
1936 queue_reply(&playlist_queue, 0); 1912 is_dirty = true;
1913
1914 stop_count--;
1915 if (is_dirty && stop_count == 0)
1916 {
1917 /* Start the background scanning after either the disk
1918 * spindown timeout or 5s, whichever is less */
1919 sleep_time = 5 * HZ;
1920#ifdef HAVE_DISK_STORAGE
1921 if (global_settings.disk_spindown > 1 &&
1922 global_settings.disk_spindown <= 5)
1923 sleep_time = (global_settings.disk_spindown - 1) * HZ;
1924#endif
1925 }
1937 break; 1926 break;
1938 1927
1939 case PLAYLIST_LOAD_POINTERS: 1928 case PLAYLIST_DC_SCAN_STOP:
1940 dc_has_dirty_pointers = true; 1929 stop_count++;
1941 break ; 1930 sleep_time = TIMEOUT_BLOCK;
1931 queue_reply(&playlist_queue, 0);
1932 break;
1942 1933
1943 /* Start the background scanning after either the disk spindown
1944 timeout or 5s, whichever is less */
1945 case SYS_TIMEOUT: 1934 case SYS_TIMEOUT:
1946 { 1935 {
1936 /* Nothing to do if there are no dcfrefs or tracks */
1947 if (!playlist->dcfrefs_handle || playlist->amount <= 0) 1937 if (!playlist->dcfrefs_handle || playlist->amount <= 0)
1948 break ; 1938 {
1949 1939 is_dirty = false;
1950 /* Check if previously loaded pointers are intact. */ 1940 sleep_time = TIMEOUT_BLOCK;
1951 if (!dc_has_dirty_pointers) 1941 logf("%s: nothing to scan", __func__);
1952 break ; 1942 break;
1943 }
1953 1944
1945 /* Retry at a later time if the dircache is not ready */
1954 struct dircache_info info; 1946 struct dircache_info info;
1955 dircache_get_info(&info); 1947 dircache_get_info(&info);
1956
1957 if (info.status != DIRCACHE_READY) 1948 if (info.status != DIRCACHE_READY)
1958 break ; 1949 {
1950 logf("%s: dircache not ready", __func__);
1951 break;
1952 }
1953
1954 logf("%s: scan start", __func__);
1955#ifdef LOGF_ENABLE
1956 long scan_start_tick = current_tick;
1957#endif
1959 1958
1960 trigger_cpu_boost(); 1959 trigger_cpu_boost();
1961 dcfrefs = core_get_data_pinned(playlist->dcfrefs_handle); 1960 dcfrefs = core_get_data_pinned(playlist->dcfrefs_handle);
1962 1961
1963 for (index = 0; index < playlist->amount 1962 for (index = 0; index < playlist->amount; index++)
1964 && queue_empty(&playlist_queue); index++)
1965 { 1963 {
1966 /* Process only pointers that are superficially stale. */ 1964 /* Process only pointers that are superficially stale. */
1967 if (dircache_search(DCS_FILEREF, &dcfrefs[index], NULL) > 0) 1965 if (dircache_search(DCS_FILEREF, &dcfrefs[index], NULL) > 0)
1968 continue ; 1966 continue;
1967
1968 /* Bail out if a command needs servicing. */
1969 if (!queue_empty(&playlist_queue))
1970 {
1971 logf("%s: scan interrupted", __func__);
1972 break;
1973 }
1969 1974
1970 control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; 1975 control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK;
1971 seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; 1976 seek = playlist->indices[index] & PLAYLIST_SEEK_MASK;
@@ -1973,9 +1978,7 @@ static void dc_thread_playlist(void)
1973 /* Load the filename from playlist file. */ 1978 /* Load the filename from playlist file. */
1974 if (get_track_filename(playlist, index, seek, 1979 if (get_track_filename(playlist, index, seek,
1975 control_file, tmp, sizeof(tmp)) < 0) 1980 control_file, tmp, sizeof(tmp)) < 0)
1976 { 1981 break;
1977 break ;
1978 }
1979 1982
1980 /* Obtain the dircache file entry cookie. */ 1983 /* Obtain the dircache file entry cookie. */
1981 dircache_search(DCS_CACHED_PATH | DCS_UPDATE_FILEREF, 1984 dircache_search(DCS_CACHED_PATH | DCS_UPDATE_FILEREF,
@@ -1985,19 +1988,26 @@ static void dc_thread_playlist(void)
1985 yield(); 1988 yield();
1986 } 1989 }
1987 1990
1991 /* If we indexed the whole playlist without being interrupted
1992 * then there are no dirty references; go to sleep. */
1993 if (index == playlist->amount)
1994 {
1995 is_dirty = false;
1996 sleep_time = TIMEOUT_BLOCK;
1997 logf("%s: scan complete", __func__);
1998 }
1999
1988 core_put_data_pinned(dcfrefs); 2000 core_put_data_pinned(dcfrefs);
1989 cancel_cpu_boost(); 2001 cancel_cpu_boost();
1990 2002
1991 if (index == playlist->amount) 2003 logf("%s: %ld ticks", __func__, current_tick - scan_start_tick);
1992 dc_has_dirty_pointers = false; 2004 break;
1993
1994 break ;
1995 } 2005 }
1996 2006
1997 case SYS_USB_CONNECTED: 2007 case SYS_USB_CONNECTED:
1998 usb_acknowledge(SYS_USB_CONNECTED_ACK); 2008 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1999 usb_wait_for_disconnect(&playlist_queue); 2009 usb_wait_for_disconnect(&playlist_queue);
2000 break ; 2010 break;
2001 } 2011 }
2002 } 2012 }
2003} 2013}
@@ -2098,6 +2108,8 @@ void playlist_init(void)
2098 queue_init(&playlist_queue, true); 2108 queue_init(&playlist_queue, true);
2099 queue_enable_queue_send(&playlist_queue, 2109 queue_enable_queue_send(&playlist_queue,
2100 &playlist_queue_sender_list, playlist_thread_id); 2110 &playlist_queue_sender_list, playlist_thread_id);
2111
2112 dc_thread_start(&current_playlist, false);
2101#endif /* HAVE_DIRCACHE */ 2113#endif /* HAVE_DIRCACHE */
2102} 2114}
2103 2115
@@ -2183,65 +2195,56 @@ int playlist_amount(void)
2183 * playlist off disk for viewing/editing. The index_buffer is used to store 2195 * playlist off disk for viewing/editing. The index_buffer is used to store
2184 * playlist indices (required for and only used if !current playlist). The 2196 * playlist indices (required for and only used if !current playlist). The
2185 * temp_buffer (if not NULL) is used as a scratchpad when loading indices. 2197 * temp_buffer (if not NULL) is used as a scratchpad when loading indices.
2198 *
2199 * XXX: This is really only usable by the playlist viewer. Never pass
2200 * playlist == NULL, that cannot and will not work.
2186 */ 2201 */
2187int playlist_create_ex(struct playlist_info* playlist, 2202int playlist_create_ex(struct playlist_info* playlist,
2188 const char* dir, const char* file, 2203 const char* dir, const char* file,
2189 void* index_buffer, int index_buffer_size, 2204 void* index_buffer, int index_buffer_size,
2190 void* temp_buffer, int temp_buffer_size) 2205 void* temp_buffer, int temp_buffer_size)
2191{ 2206{
2192 if (!playlist) 2207 /* Initialize playlist structure */
2193 { 2208 int r = rand() % 10;
2194 playlist = &current_playlist;
2195 playlist_mutex_lock(&(playlist->mutex));
2196 playlist->last_shuffled_start = playlist->amount;
2197 playlist_mutex_unlock(&(playlist->mutex));
2198 }
2199 else
2200 {
2201 /* Initialize playlist structure */
2202 int r = rand() % 10;
2203 2209
2204 /* Use random name for control file */ 2210 /* Use random name for control file */
2205 snprintf(playlist->control_filename, sizeof(playlist->control_filename), 2211 snprintf(playlist->control_filename, sizeof(playlist->control_filename),
2206 "%s.%d", PLAYLIST_CONTROL_FILE, r); 2212 "%s.%d", PLAYLIST_CONTROL_FILE, r);
2207 playlist->fd = -1; 2213 playlist->fd = -1;
2208 playlist->control_fd = -1; 2214 playlist->control_fd = -1;
2209 2215
2210 if (index_buffer) 2216 if (index_buffer)
2211 { 2217 {
2212 int num_indices = index_buffer_size / 2218 int num_indices = index_buffer_size /
2213 playlist_get_required_bufsz(playlist, false, 1); 2219 playlist_get_required_bufsz(playlist, false, 1);
2214 2220
2215 if (num_indices > global_settings.max_files_in_playlist) 2221 if (num_indices > global_settings.max_files_in_playlist)
2216 num_indices = global_settings.max_files_in_playlist; 2222 num_indices = global_settings.max_files_in_playlist;
2217 2223
2218 playlist->max_playlist_size = num_indices; 2224 playlist->max_playlist_size = num_indices;
2219 playlist->indices = index_buffer; 2225 playlist->indices = index_buffer;
2220#ifdef HAVE_DIRCACHE 2226#ifdef HAVE_DIRCACHE
2221 playlist->dcfrefs_handle = 0; 2227 playlist->dcfrefs_handle = 0;
2222#endif 2228#endif
2223 } 2229 }
2224 else 2230 else
2225 { 2231 {
2226 /* FIXME not sure if it's safe to share index buffers */ 2232 /* FIXME not sure if it's safe to share index buffers */
2227 playlist->max_playlist_size = current_playlist.max_playlist_size; 2233 playlist->max_playlist_size = current_playlist.max_playlist_size;
2228 playlist->indices = current_playlist.indices; 2234 playlist->indices = current_playlist.indices;
2229#ifdef HAVE_DIRCACHE 2235#ifdef HAVE_DIRCACHE
2230 playlist->dcfrefs_handle = 0; 2236 playlist->dcfrefs_handle = 0;
2231#endif 2237#endif
2232 }
2233
2234 chunk_alloc_free(&playlist->name_chunk_buffer);
2235 } 2238 }
2236 2239
2240 chunk_alloc_free(&playlist->name_chunk_buffer);
2241
2237 new_playlist_unlocked(playlist, dir, file); 2242 new_playlist_unlocked(playlist, dir, file);
2238 2243
2244 /* load the playlist file */
2239 if (file) 2245 if (file)
2240 {
2241 /* load the playlist file */
2242 add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size); 2246 add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size);
2243 dc_load_playlist_pointers(); 2247
2244 }
2245 return 0; 2248 return 0;
2246} 2249}
2247 2250
@@ -2251,6 +2254,10 @@ int playlist_create_ex(struct playlist_info* playlist,
2251int playlist_create(const char *dir, const char *file) 2254int playlist_create(const char *dir, const char *file)
2252{ 2255{
2253 struct playlist_info* playlist = &current_playlist; 2256 struct playlist_info* playlist = &current_playlist;
2257 int status = 0;
2258
2259 dc_thread_stop(playlist);
2260 playlist_mutex_lock(&playlist->mutex);
2254 2261
2255 new_playlist_unlocked(playlist, dir, file); 2262 new_playlist_unlocked(playlist, dir, file);
2256 2263
@@ -2266,18 +2273,20 @@ int playlist_create(const char *dir, const char *file)
2266 buflen = ALIGN_DOWN(buflen, 512); /* to avoid partial sector I/O */ 2273 buflen = ALIGN_DOWN(buflen, 512); /* to avoid partial sector I/O */
2267 /* load the playlist file */ 2274 /* load the playlist file */
2268 add_indices_to_playlist(playlist, buf, buflen); 2275 add_indices_to_playlist(playlist, buf, buflen);
2269 dc_load_playlist_pointers();
2270 core_free(handle); 2276 core_free(handle);
2271 } 2277 }
2272 else 2278 else
2273 { 2279 {
2274 /* should not happen -- happens if plugin takes audio buffer */ 2280 /* should not happen -- happens if plugin takes audio buffer */
2275 splashf(HZ * 2, "%s(): OOM", __func__); 2281 splashf(HZ * 2, "%s(): OOM", __func__);
2276 return -1; 2282 status = -1;
2277 } 2283 }
2278 } 2284 }
2279 2285
2280 return 0; 2286 playlist_mutex_unlock(&playlist->mutex);
2287 dc_thread_start(playlist, true);
2288
2289 return status;
2281} 2290}
2282 2291
2283/* Returns false if 'steps' is out of bounds, else true */ 2292/* Returns false if 'steps' is out of bounds, else true */
@@ -2331,18 +2340,24 @@ int playlist_delete(struct playlist_info* playlist, int index)
2331 if (!playlist) 2340 if (!playlist)
2332 playlist = &current_playlist; 2341 playlist = &current_playlist;
2333 2342
2343 dc_thread_stop(playlist);
2344 playlist_mutex_lock(&playlist->mutex);
2345
2334 if (check_control(playlist) < 0) 2346 if (check_control(playlist) < 0)
2335 { 2347 {
2336 notify_control_access_error(); 2348 notify_control_access_error();
2337 return -1; 2349 result = -1;
2350 goto out;
2338 } 2351 }
2339 2352
2340 dc_discard_playlist_pointers();
2341
2342 if (index == PLAYLIST_DELETE_CURRENT) 2353 if (index == PLAYLIST_DELETE_CURRENT)
2343 index = playlist->index; 2354 index = playlist->index;
2344 2355
2345 result = remove_track_from_playlist(playlist, index, true); 2356 result = remove_track_unlocked(playlist, index, true);
2357
2358out:
2359 playlist_mutex_unlock(&playlist->mutex);
2360 dc_thread_start(playlist, false);
2346 2361
2347 if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && 2362 if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) &&
2348 playlist->started) 2363 playlist->started)
@@ -2607,10 +2622,14 @@ int playlist_insert_directory(struct playlist_info* playlist,
2607 if (!playlist) 2622 if (!playlist)
2608 playlist = &current_playlist; 2623 playlist = &current_playlist;
2609 2624
2625 dc_thread_stop(playlist);
2626 playlist_mutex_lock(&playlist->mutex);
2627
2610 if (check_control(playlist) < 0) 2628 if (check_control(playlist) < 0)
2611 { 2629 {
2612 notify_control_access_error(); 2630 notify_control_access_error();
2613 return -1; 2631 result = -1;
2632 goto out;
2614 } 2633 }
2615 2634
2616 if (position == PLAYLIST_REPLACE) 2635 if (position == PLAYLIST_REPLACE)
@@ -2618,11 +2637,12 @@ int playlist_insert_directory(struct playlist_info* playlist,
2618 if (playlist_remove_all_tracks(playlist) == 0) 2637 if (playlist_remove_all_tracks(playlist) == 0)
2619 position = PLAYLIST_INSERT_LAST; 2638 position = PLAYLIST_INSERT_LAST;
2620 else 2639 else
2621 return -1; 2640 {
2641 result = -1;
2642 goto out;
2643 }
2622 } 2644 }
2623 2645
2624 dc_discard_playlist_pointers();
2625
2626 if (queue) 2646 if (queue)
2627 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); 2647 count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT);
2628 else 2648 else
@@ -2646,11 +2666,13 @@ int playlist_insert_directory(struct playlist_info* playlist,
2646 2666
2647 display_playlist_count(context.count, count_str, true); 2667 display_playlist_count(context.count, count_str, true);
2648 2668
2669out:
2670 playlist_mutex_unlock(&playlist->mutex);
2671 dc_thread_start(playlist, true);
2672
2649 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 2673 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
2650 audio_flush_and_reload_tracks(); 2674 audio_flush_and_reload_tracks();
2651 2675
2652 dc_load_playlist_pointers();
2653
2654 return result; 2676 return result;
2655} 2677}
2656 2678
@@ -2673,10 +2695,9 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
2673 if (!playlist) 2695 if (!playlist)
2674 playlist = &current_playlist; 2696 playlist = &current_playlist;
2675 2697
2698 dc_thread_stop(playlist);
2676 playlist_mutex_lock(&(playlist->mutex)); 2699 playlist_mutex_lock(&(playlist->mutex));
2677 2700
2678 dc_discard_playlist_pointers();
2679
2680 cpu_boost(true); 2701 cpu_boost(true);
2681 2702
2682 if (check_control(playlist) < 0) 2703 if (check_control(playlist) < 0)
@@ -2780,13 +2801,13 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
2780 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 2801 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
2781 audio_flush_and_reload_tracks(); 2802 audio_flush_and_reload_tracks();
2782 2803
2783 dc_load_playlist_pointers();
2784 result = 0; 2804 result = 0;
2785 2805
2786out: 2806out:
2787 cpu_boost(false); 2807 cpu_boost(false);
2788 2808
2789 playlist_mutex_unlock(&(playlist->mutex)); 2809 playlist_mutex_unlock(&(playlist->mutex));
2810 dc_thread_start(playlist, true);
2790 2811
2791 return result; 2812 return result;
2792} 2813}
@@ -2803,10 +2824,9 @@ int playlist_insert_track(struct playlist_info* playlist, const char *filename,
2803 if (!playlist) 2824 if (!playlist)
2804 playlist = &current_playlist; 2825 playlist = &current_playlist;
2805 2826
2827 dc_thread_stop(playlist);
2806 playlist_mutex_lock(&(playlist->mutex)); 2828 playlist_mutex_lock(&(playlist->mutex));
2807 2829
2808 dc_discard_playlist_pointers();
2809
2810 if (check_control(playlist) < 0) 2830 if (check_control(playlist) < 0)
2811 { 2831 {
2812 notify_control_access_error(); 2832 notify_control_access_error();
@@ -2820,11 +2840,10 @@ int playlist_insert_track(struct playlist_info* playlist, const char *filename,
2820 * bunch of files from tagcache, syncing after every file wouldn't be 2840 * bunch of files from tagcache, syncing after every file wouldn't be
2821 * a good thing to do. */ 2841 * a good thing to do. */
2822 if (sync && result >= 0) 2842 if (sync && result >= 0)
2823 {
2824 playlist_sync(playlist); 2843 playlist_sync(playlist);
2825 }
2826 2844
2827 playlist_mutex_unlock(&(playlist->mutex)); 2845 playlist_mutex_unlock(&(playlist->mutex));
2846 dc_thread_start(playlist, true);
2828 2847
2829 return result; 2848 return result;
2830} 2849}
@@ -2867,12 +2886,13 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
2867 if (!playlist) 2886 if (!playlist)
2868 playlist = &current_playlist; 2887 playlist = &current_playlist;
2869 2888
2889 dc_thread_stop(playlist);
2870 playlist_mutex_lock(&(playlist->mutex)); 2890 playlist_mutex_lock(&(playlist->mutex));
2871 2891
2872 if (check_control(playlist) < 0) 2892 if (check_control(playlist) < 0)
2873 { 2893 {
2874 notify_control_access_error(); 2894 notify_control_access_error();
2875 goto out;; 2895 goto out;
2876 } 2896 }
2877 2897
2878 if (index == new_index) 2898 if (index == new_index)
@@ -2919,8 +2939,6 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
2919 goto out; 2939 goto out;
2920 } 2940 }
2921 2941
2922 dc_discard_playlist_pointers();
2923
2924 /* We want to insert the track at the position that was specified by 2942 /* We want to insert the track at the position that was specified by
2925 new_index. This may be different then new_index because of the 2943 new_index. This may be different then new_index because of the
2926 shifting that will occur after the delete. 2944 shifting that will occur after the delete.
@@ -2929,68 +2947,59 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
2929 r = rotate_index(playlist, new_index); 2947 r = rotate_index(playlist, new_index);
2930 2948
2931 /* Delete track from original position */ 2949 /* Delete track from original position */
2932 result = remove_track_from_playlist(playlist, index, true); 2950 result = remove_track_unlocked(playlist, index, true);
2951 if (result == -1)
2952 goto out;
2933 2953
2934 if (result != -1) 2954 if (r == 0)/* First index */
2935 { 2955 {
2936 if (r == 0)/* First index */ 2956 new_index = PLAYLIST_PREPEND;
2937 { 2957 }
2938 new_index = PLAYLIST_PREPEND; 2958 else if (r == playlist->amount)
2939 } 2959 {
2940 else if (r == playlist->amount) 2960 /* Append */
2941 { 2961 new_index = PLAYLIST_INSERT_LAST;
2942 /* Append */ 2962 }
2943 new_index = PLAYLIST_INSERT_LAST; 2963 else /* Calculate index of desired position */
2944 } 2964 {
2945 else /* Calculate index of desired position */ 2965 new_index = (r+playlist->first_index)%playlist->amount;
2946 { 2966 }
2947 new_index = (r+playlist->first_index)%playlist->amount;
2948 }
2949
2950 result = add_track_to_playlist_unlocked(playlist, filename,
2951 new_index, queue, -1);
2952 2967
2953 if (result != -1) 2968 result = add_track_to_playlist_unlocked(playlist, filename,
2954 { 2969 new_index, queue, -1);
2955 if (current) 2970 if (result == -1)
2956 { 2971 goto out;
2957 /* Moved the current track */
2958 switch (new_index)
2959 {
2960 case PLAYLIST_PREPEND:
2961 playlist->index = playlist->first_index;
2962 break;
2963 case PLAYLIST_INSERT_LAST:
2964 playlist->index = playlist->first_index - 1;
2965 if (playlist->index < 0)
2966 playlist->index += playlist->amount;
2967 break;
2968 default:
2969 playlist->index = new_index;
2970 break;
2971 }
2972 }
2973 else if ((displace_current) && (new_index != PLAYLIST_PREPEND))
2974 {
2975 /* make the index point to the currently playing track */
2976 playlist->index++;
2977 }
2978 2972
2979 playlist_mutex_unlock(&(playlist->mutex)); 2973 if (current)
2980 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 2974 {
2981 audio_flush_and_reload_tracks(); 2975 /* Moved the current track */
2982 } 2976 switch (new_index)
2983 else
2984 { 2977 {
2985 playlist_mutex_unlock(&(playlist->mutex)); 2978 case PLAYLIST_PREPEND:
2979 playlist->index = playlist->first_index;
2980 break;
2981 case PLAYLIST_INSERT_LAST:
2982 playlist->index = playlist->first_index - 1;
2983 if (playlist->index < 0)
2984 playlist->index += playlist->amount;
2985 break;
2986 default:
2987 playlist->index = new_index;
2988 break;
2986 } 2989 }
2987 } 2990 }
2988 2991 else if ((displace_current) && (new_index != PLAYLIST_PREPEND))
2989 dc_load_playlist_pointers(); 2992 {
2990 return result; 2993 /* make the index point to the currently playing track */
2994 playlist->index++;
2995 }
2991 2996
2992out: 2997out:
2993 playlist_mutex_unlock(&(playlist->mutex)); 2998 playlist_mutex_unlock(&(playlist->mutex));
2999 dc_thread_start(playlist, true);
3000
3001 if (result != -1 && playlist->started && (audio_status() & AUDIO_STATUS_PLAY))
3002 audio_flush_and_reload_tracks();
2994 3003
2995 return result; 3004 return result;
2996} 3005}
@@ -3024,7 +3033,8 @@ int playlist_next(int steps)
3024{ 3033{
3025 struct playlist_info* playlist = &current_playlist; 3034 struct playlist_info* playlist = &current_playlist;
3026 3035
3027 playlist_mutex_lock(&(playlist->mutex)); 3036 dc_thread_stop(playlist);
3037 playlist_mutex_lock(&playlist->mutex);
3028 3038
3029 int index; 3039 int index;
3030 3040
@@ -3036,8 +3046,6 @@ int playlist_next(int steps)
3036 { 3046 {
3037 int i, j; 3047 int i, j;
3038 3048
3039 dc_discard_playlist_pointers();
3040
3041 /* We need to delete all the queued songs */ 3049 /* We need to delete all the queued songs */
3042 for (i=0, j=steps; i<j; i++) 3050 for (i=0, j=steps; i<j; i++)
3043 { 3051 {
@@ -3045,7 +3053,7 @@ int playlist_next(int steps)
3045 3053
3046 if (index >= 0 && playlist->indices[index] & PLAYLIST_QUEUE_MASK) 3054 if (index >= 0 && playlist->indices[index] & PLAYLIST_QUEUE_MASK)
3047 { 3055 {
3048 remove_track_from_playlist(playlist, index, true); 3056 remove_track_unlocked(playlist, index, true);
3049 steps--; /* one less track */ 3057 steps--; /* one less track */
3050 } 3058 }
3051 } 3059 }
@@ -3062,7 +3070,7 @@ int playlist_next(int steps)
3062 /* Repeat shuffle mode. Re-shuffle playlist and resume play */ 3070 /* Repeat shuffle mode. Re-shuffle playlist and resume play */
3063 playlist->first_index = 0; 3071 playlist->first_index = 0;
3064 sort_playlist_unlocked(playlist, false, false); 3072 sort_playlist_unlocked(playlist, false, false);
3065 randomise_playlist(playlist, current_tick, false, true); 3073 randomise_playlist_unlocked(playlist, current_tick, false, true);
3066 3074
3067 playlist->started = true; 3075 playlist->started = true;
3068 playlist->index = 0; 3076 playlist->index = 0;
@@ -3071,9 +3079,7 @@ int playlist_next(int steps)
3071 else if (playlist->in_ram && global_settings.next_folder) 3079 else if (playlist->in_ram && global_settings.next_folder)
3072 { 3080 {
3073 /* we switch playlists here */ 3081 /* we switch playlists here */
3074 playlist_mutex_unlock(&(playlist->mutex));
3075 index = create_and_play_dir(steps, true); 3082 index = create_and_play_dir(steps, true);
3076 playlist_mutex_lock(&(playlist->mutex));
3077 if (index >= 0) 3083 if (index >= 0)
3078 { 3084 {
3079 playlist->index = index; 3085 playlist->index = index;
@@ -3110,7 +3116,8 @@ int playlist_next(int steps)
3110 } 3116 }
3111 3117
3112out: 3118out:
3113 playlist_mutex_unlock(&(playlist->mutex)); 3119 playlist_mutex_unlock(&playlist->mutex);
3120 dc_thread_start(playlist, true);
3114 3121
3115 return index; 3122 return index;
3116} 3123}
@@ -3179,7 +3186,11 @@ const char* playlist_peek(int steps, char* buf, size_t buf_size)
3179 return temp_ptr; 3186 return temp_ptr;
3180} 3187}
3181 3188
3182/* shuffle currently playing playlist */ 3189/*
3190 * shuffle currently playing playlist
3191 *
3192 * TODO: Merge this with playlist_shuffle()?
3193 */
3183int playlist_randomise(struct playlist_info* playlist, unsigned int seed, 3194int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
3184 bool start_current) 3195 bool start_current)
3185{ 3196{
@@ -3188,12 +3199,12 @@ int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
3188 if (!playlist) 3199 if (!playlist)
3189 playlist = &current_playlist; 3200 playlist = &current_playlist;
3190 3201
3202 dc_thread_stop(playlist);
3191 playlist_mutex_lock(&(playlist->mutex)); 3203 playlist_mutex_lock(&(playlist->mutex));
3192 3204
3193 check_control(playlist); 3205 check_control(playlist);
3194 3206
3195 result = randomise_playlist(playlist, seed, start_current, true); 3207 result = randomise_playlist_unlocked(playlist, seed, start_current, true);
3196
3197 if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && 3208 if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) &&
3198 playlist->started) 3209 playlist->started)
3199 { 3210 {
@@ -3201,6 +3212,7 @@ int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
3201 } 3212 }
3202 3213
3203 playlist_mutex_unlock(&(playlist->mutex)); 3214 playlist_mutex_unlock(&(playlist->mutex));
3215 dc_thread_start(playlist, true);
3204 3216
3205 return result; 3217 return result;
3206} 3218}
@@ -3208,6 +3220,8 @@ int playlist_randomise(struct playlist_info* playlist, unsigned int seed,
3208/* 3220/*
3209 * Removes all tracks, from the playlist, leaving the presently playing 3221 * Removes all tracks, from the playlist, leaving the presently playing
3210 * track queued. 3222 * track queued.
3223 *
3224 * TODO: This is insanely slow for huge playlists. Must fix.
3211 */ 3225 */
3212int playlist_remove_all_tracks(struct playlist_info *playlist) 3226int playlist_remove_all_tracks(struct playlist_info *playlist)
3213{ 3227{
@@ -3216,20 +3230,25 @@ int playlist_remove_all_tracks(struct playlist_info *playlist)
3216 if (playlist == NULL) 3230 if (playlist == NULL)
3217 playlist = &current_playlist; 3231 playlist = &current_playlist;
3218 3232
3219 dc_discard_playlist_pointers(); 3233 dc_thread_stop(playlist);
3234 playlist_mutex_lock(&playlist->mutex);
3220 3235
3221 while (playlist->index > 0) 3236 while (playlist->index > 0)
3222 if ((result = remove_track_from_playlist(playlist, 0, true)) < 0) 3237 if ((result = remove_track_unlocked(playlist, 0, true)) < 0)
3223 return result; 3238 goto out;
3224 3239
3225 while (playlist->amount > 1) 3240 while (playlist->amount > 1)
3226 if ((result = remove_track_from_playlist(playlist, 1, true)) < 0) 3241 if ((result = remove_track_unlocked(playlist, 1, true)) < 0)
3227 return result; 3242 goto out;
3228 3243
3229 if (playlist->amount == 1) { 3244 if (playlist->amount == 1) {
3230 playlist->indices[0] |= PLAYLIST_QUEUED; 3245 playlist->indices[0] |= PLAYLIST_QUEUED;
3231 } 3246 }
3232 3247
3248out:
3249 playlist_mutex_unlock(&playlist->mutex);
3250 dc_thread_start(playlist, false);
3251
3233 return 0; 3252 return 0;
3234} 3253}
3235 3254
@@ -3253,7 +3272,8 @@ int playlist_resume(void)
3253 splash(0, ID2P(LANG_WAIT)); 3272 splash(0, ID2P(LANG_WAIT));
3254 3273
3255 struct playlist_info* playlist = &current_playlist; 3274 struct playlist_info* playlist = &current_playlist;
3256 playlist_mutex_lock(&(playlist->mutex)); 3275 dc_thread_stop(playlist);
3276 playlist_mutex_lock(&playlist->mutex);
3257 3277
3258 if (core_allocatable() < (1 << 10)) 3278 if (core_allocatable() < (1 << 10))
3259 talk_buffer_set_policy(TALK_BUFFER_LOOSE); /* back off voice buffer */ 3279 talk_buffer_set_policy(TALK_BUFFER_LOOSE); /* back off voice buffer */
@@ -3437,8 +3457,7 @@ int playlist_resume(void)
3437 3457
3438 position = atoi(str1); 3458 position = atoi(str1);
3439 3459
3440 if (remove_track_from_playlist(playlist, position, 3460 if (remove_track_unlocked(playlist, position, false) < 0)
3441 false) < 0)
3442 { 3461 {
3443 result = -7; 3462 result = -7;
3444 goto out; 3463 goto out;
@@ -3467,7 +3486,7 @@ int playlist_resume(void)
3467 seed = atoi(str1); 3486 seed = atoi(str1);
3468 playlist->first_index = atoi(str2); 3487 playlist->first_index = atoi(str2);
3469 3488
3470 if (randomise_playlist(playlist, seed, false, 3489 if (randomise_playlist_unlocked(playlist, seed, false,
3471 false) < 0) 3490 false) < 0)
3472 { 3491 {
3473 result = -9; 3492 result = -9;
@@ -3647,10 +3666,9 @@ int playlist_resume(void)
3647 } 3666 }
3648 } 3667 }
3649 3668
3650 dc_load_playlist_pointers();
3651
3652out: 3669out:
3653 playlist_mutex_unlock(&(playlist->mutex)); 3670 playlist_mutex_unlock(&playlist->mutex);
3671 dc_thread_start(playlist, true);
3654 3672
3655 talk_buffer_set_policy(TALK_BUFFER_DEFAULT); 3673 talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
3656 core_free(handle); 3674 core_free(handle);
@@ -3810,7 +3828,8 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3810 { 3828 {
3811 strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */ 3829 strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */
3812 3830
3813 playlist_mutex_lock(&(playlist->mutex)); 3831 dc_thread_stop(playlist);
3832 playlist_mutex_lock(&playlist->mutex);
3814 3833
3815 if (!rename(path, tmp_buf)) 3834 if (!rename(path, tmp_buf))
3816 { 3835 {
@@ -3822,7 +3841,6 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3822 close(playlist->fd); 3841 close(playlist->fd);
3823 playlist->fd = fd; 3842 playlist->fd = fd;
3824 fd = -1; 3843 fd = -1;
3825 dc_discard_playlist_pointers();
3826 3844
3827 if (!reparse) 3845 if (!reparse)
3828 { 3846 {
@@ -3848,11 +3866,11 @@ int playlist_save(struct playlist_info* playlist, char *filename,
3848 /* we need to recreate control because inserted tracks are 3866 /* we need to recreate control because inserted tracks are
3849 now part of the playlist and shuffle has been invalidated */ 3867 now part of the playlist and shuffle has been invalidated */
3850 result = recreate_control_unlocked(playlist); 3868 result = recreate_control_unlocked(playlist);
3851 dc_load_playlist_pointers();
3852 } 3869 }
3853 } 3870 }
3854 3871
3855 playlist_mutex_unlock(&(playlist->mutex)); 3872 playlist_mutex_unlock(&playlist->mutex);
3873 dc_thread_start(playlist, true);
3856 } 3874 }
3857 3875
3858 if (fd >= 0) 3876 if (fd >= 0)
@@ -3876,7 +3894,8 @@ int playlist_set_current(struct playlist_info* playlist)
3876 if (!playlist || (check_control(playlist) < 0)) 3894 if (!playlist || (check_control(playlist) < 0))
3877 return result; 3895 return result;
3878 3896
3879 playlist_mutex_lock(&(current_playlist.mutex)); 3897 dc_thread_stop(&current_playlist);
3898 playlist_mutex_lock(&current_playlist.mutex);
3880 3899
3881 empty_playlist_unlocked(&current_playlist, false); 3900 empty_playlist_unlocked(&current_playlist, false);
3882 3901
@@ -3927,7 +3946,8 @@ int playlist_set_current(struct playlist_info* playlist)
3927 result = 0; 3946 result = 0;
3928 3947
3929out: 3948out:
3930 playlist_mutex_unlock(&(current_playlist.mutex)); 3949 playlist_mutex_unlock(&current_playlist.mutex);
3950 dc_thread_start(&current_playlist, true);
3931 3951
3932 return result; 3952 return result;
3933} 3953}
@@ -3946,9 +3966,11 @@ void playlist_set_last_shuffled_start(void)
3946int playlist_shuffle(int random_seed, int start_index) 3966int playlist_shuffle(int random_seed, int start_index)
3947{ 3967{
3948 struct playlist_info* playlist = &current_playlist; 3968 struct playlist_info* playlist = &current_playlist;
3949 playlist_mutex_lock(&(playlist->mutex));
3950 bool start_current = false; 3969 bool start_current = false;
3951 3970
3971 dc_thread_stop(playlist);
3972 playlist_mutex_lock(&(playlist->mutex));
3973
3952 if (start_index >= 0 && global_settings.play_selected) 3974 if (start_index >= 0 && global_settings.play_selected)
3953 { 3975 {
3954 /* store the seek position before the shuffle */ 3976 /* store the seek position before the shuffle */
@@ -3956,8 +3978,11 @@ int playlist_shuffle(int random_seed, int start_index)
3956 start_current = true; 3978 start_current = true;
3957 } 3979 }
3958 3980
3959 randomise_playlist(playlist, random_seed, start_current, true); 3981 randomise_playlist_unlocked(playlist, random_seed, start_current, true);
3982
3960 playlist_mutex_unlock(&(playlist->mutex)); 3983 playlist_mutex_unlock(&(playlist->mutex));
3984 dc_thread_start(playlist, true);
3985
3961 return playlist->index; 3986 return playlist->index;
3962} 3987}
3963 3988
@@ -3993,7 +4018,8 @@ int playlist_sort(struct playlist_info* playlist, bool start_current)
3993 if (!playlist) 4018 if (!playlist)
3994 playlist = &current_playlist; 4019 playlist = &current_playlist;
3995 4020
3996 playlist_mutex_lock(&(playlist->mutex)); 4021 dc_thread_stop(playlist);
4022 playlist_mutex_lock(&playlist->mutex);
3997 4023
3998 check_control(playlist); 4024 check_control(playlist);
3999 result = sort_playlist_unlocked(playlist, start_current, true); 4025 result = sort_playlist_unlocked(playlist, start_current, true);
@@ -4001,7 +4027,8 @@ int playlist_sort(struct playlist_info* playlist, bool start_current)
4001 if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 4027 if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
4002 audio_flush_and_reload_tracks(); 4028 audio_flush_and_reload_tracks();
4003 4029
4004 playlist_mutex_unlock(&(playlist->mutex)); 4030 playlist_mutex_unlock(&playlist->mutex);
4031 dc_thread_start(playlist, true);
4005 return result; 4032 return result;
4006} 4033}
4007 4034
@@ -4032,8 +4059,6 @@ void playlist_sync(struct playlist_info* playlist)
4032 sync_control(playlist, false); 4059 sync_control(playlist, false);
4033 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 4060 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
4034 audio_flush_and_reload_tracks(); 4061 audio_flush_and_reload_tracks();
4035
4036 dc_load_playlist_pointers();
4037} 4062}
4038 4063
4039/* Update resume info for current playing song. Returns -1 on error. */ 4064/* Update resume info for current playing song. Returns -1 on error. */