diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-08-15 23:05:49 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-08-15 23:05:49 +0200 |
commit | 28e67e0c1496b7bb166a0acfb176690f219101ca (patch) | |
tree | b30fcbc9fd72f4aed6135478113fcd6dadf37912 /src/sound.c | |
parent | 5dd143e22333a1c320fcf330f6c5061269bd1a17 (diff) | |
download | vim-git-28e67e0c1496b7bb166a0acfb176690f219101ca.tar.gz |
patch 8.1.1851: crash when sound_playfile() callback plays soundv8.1.1851
Problem: Crash when sound_playfile() callback plays sound.
Solution: Invoke callback later from event loop.
Diffstat (limited to 'src/sound.c')
-rw-r--r-- | src/sound.c | 87 |
1 files changed, 75 insertions, 12 deletions
diff --git a/src/sound.c b/src/sound.c index 92618a9f3..69bbc5e6d 100644 --- a/src/sound.c +++ b/src/sound.c @@ -30,6 +30,16 @@ struct soundcb_S { static soundcb_T *first_callback = NULL; +/* + * Return TRUE when a sound callback has been created, it may be invoked when + * the sound finishes playing. Also see has_sound_callback_in_queue(). + */ + int +has_any_sound_callback(void) +{ + return first_callback != NULL; +} + static soundcb_T * get_sound_callback(typval_T *arg) { @@ -85,6 +95,24 @@ delete_sound_callback(soundcb_T *soundcb) static ca_context *context = NULL; +// Structure to store info about a sound callback to be invoked soon. +typedef struct soundcb_queue_S soundcb_queue_T; + +struct soundcb_queue_S { + soundcb_queue_T *scb_next; + uint32_t scb_id; // ID of the sound + int scb_result; // CA_ value + soundcb_T *scb_callback; // function to call +}; + +// Queue of callbacks to invoke from the main loop. +static soundcb_queue_T *callback_queue = NULL; + +/* + * Add a callback to the queue of callbacks to invoke later from the main loop. + * That is because the callback may be called from another thread and invoking + * another sound function may cause trouble. + */ static void sound_callback( ca_context *c UNUSED, @@ -92,23 +120,58 @@ sound_callback( int error_code, void *userdata) { - soundcb_T *soundcb = (soundcb_T *)userdata; - typval_T argv[3]; - typval_T rettv; - - argv[0].v_type = VAR_NUMBER; - argv[0].vval.v_number = id; - argv[1].v_type = VAR_NUMBER; - argv[1].vval.v_number = error_code == CA_SUCCESS ? 0 + soundcb_T *soundcb = (soundcb_T *)userdata; + soundcb_queue_T *scb; + + scb = ALLOC_ONE(soundcb_queue_T); + if (scb == NULL) + return; + scb->scb_next = callback_queue; + callback_queue = scb; + scb->scb_id = id; + scb->scb_result = error_code == CA_SUCCESS ? 0 : error_code == CA_ERROR_CANCELED || error_code == CA_ERROR_DESTROYED ? 1 : 2; - argv[2].v_type = VAR_UNKNOWN; + scb->scb_callback = soundcb; +} - call_callback(&soundcb->snd_callback, -1, &rettv, 2, argv); - clear_tv(&rettv); +/* + * Return TRUE if there is a sound callback to be called. + */ + int +has_sound_callback_in_queue(void) +{ + return callback_queue != NULL; +} + +/* + * Invoke queued sound callbacks. + */ + void +invoke_sound_callback(void) +{ + soundcb_queue_T *scb; + typval_T argv[3]; + typval_T rettv; + + + while (callback_queue != NULL) + { + scb = callback_queue; + callback_queue = scb->scb_next; - delete_sound_callback(soundcb); + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = scb->scb_id; + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = scb->scb_result; + argv[2].v_type = VAR_UNKNOWN; + + call_callback(&scb->scb_callback->snd_callback, -1, &rettv, 2, argv); + clear_tv(&rettv); + + delete_sound_callback(scb->scb_callback); + } redraw_after_callback(TRUE); } |