High priority scheduling was not working in alsa, oss and pthread drivers. Converted to using fluid_thread_t.

Removed prio parameter from new_fluid_thread (now just using prio_level of 0 to disable).
Fixed non-blocking in alsa_raw and alsa_seq drivers.
Added polling and non-blocking to OSS MIDI driver.
This commit is contained in:
Josh Green 2009-10-30 21:49:54 +00:00
parent 997b660805
commit b46061bfe7
8 changed files with 134 additions and 503 deletions

View file

@ -34,7 +34,6 @@
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@ -60,7 +59,7 @@ typedef struct {
fluid_audio_func_t callback;
void* data;
int buffer_size;
pthread_t thread;
fluid_thread_t *thread;
int cont;
} fluid_alsa_audio_driver_t;
@ -72,15 +71,15 @@ fluid_audio_driver_t* new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p);
void fluid_alsa_audio_driver_settings(fluid_settings_t* settings);
static void* fluid_alsa_audio_run_float(void* d);
static void* fluid_alsa_audio_run_s16(void* d);
static void fluid_alsa_audio_run_float(void* d);
static void fluid_alsa_audio_run_s16(void* d);
struct fluid_alsa_formats_t {
char* name;
snd_pcm_format_t format;
snd_pcm_access_t access;
void* (*run)(void* d);
fluid_thread_func_t run;
};
struct fluid_alsa_formats_t fluid_alsa_formats[] = {
@ -106,7 +105,7 @@ typedef struct {
snd_rawmidi_t *rawmidi_in;
struct pollfd *pfd;
int npfd;
pthread_t thread;
fluid_thread_t *thread;
int status;
unsigned char buffer[BUFFER_LENGTH];
fluid_midi_parser_t* parser;
@ -118,7 +117,7 @@ fluid_midi_driver_t* new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
void* event_handler_data);
int delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p);
static void* fluid_alsa_midi_run(void* d);
static void fluid_alsa_midi_run(void* d);
/*
@ -130,7 +129,7 @@ typedef struct {
snd_seq_t *seq_handle;
struct pollfd *pfd;
int npfd;
pthread_t thread;
fluid_thread_t *thread;
int status;
int port_count;
} fluid_alsa_seq_driver_t;
@ -139,7 +138,7 @@ fluid_midi_driver_t* new_fluid_alsa_seq_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler,
void* data);
int delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p);
static void* fluid_alsa_seq_run(void* d);
static void fluid_alsa_seq_run(void* d);
/**************************************************************
*
@ -168,9 +167,7 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
double sample_rate;
int periods, period_size;
char* device = NULL;
pthread_attr_t attr;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int i, err, dir = 0;
snd_pcm_hw_params_t* hwparams;
@ -306,47 +303,10 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
/* Create the audio thread */
dev->thread = new_fluid_thread (fluid_alsa_formats[i].run, dev, realtime_prio, FALSE);
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
if (!dev->thread)
goto error_recovery;
}
/* The pthread_create man page explains that
pthread_attr_setschedpolicy returns an error if the user is not
permitted the set SCHED_FIFO. It seems however that no error is
returned but pthread_create fails instead. That's why I try to
create the thread twice in a while loop. */
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam(&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_alsa_formats[i].run, (void*) dev);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
goto error_recovery;
}
}
break;
}
if (device) FLUID_FREE (device); /* -- free device name */
@ -368,12 +328,8 @@ int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p)
dev->cont = 0;
if (dev->thread) {
if (pthread_join(dev->thread, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to join the audio thread");
return FLUID_FAILED;
}
}
if (dev->thread)
fluid_thread_join (dev->thread);
if (dev->pcm) {
snd_pcm_state_t state = snd_pcm_state(dev->pcm);
@ -420,7 +376,7 @@ static int fluid_alsa_handle_write_error (snd_pcm_t *pcm, int errval)
return FLUID_OK;
}
static void* fluid_alsa_audio_run_float(void* d)
static void fluid_alsa_audio_run_float (void *d)
{
fluid_alsa_audio_driver_t* dev = (fluid_alsa_audio_driver_t*) d;
fluid_synth_t *synth = (fluid_synth_t *)(dev->data);
@ -436,7 +392,7 @@ static void* fluid_alsa_audio_run_float(void* d)
if ((left == NULL) || (right == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory.");
return NULL;
return;
}
if (snd_pcm_nonblock(dev->pcm, 0) != 0) { /* double negation */
@ -498,11 +454,9 @@ static void* fluid_alsa_audio_run_float(void* d)
FLUID_FREE(left);
FLUID_FREE(right);
return NULL;
}
static void* fluid_alsa_audio_run_s16(void* d)
static void fluid_alsa_audio_run_s16 (void *d)
{
fluid_alsa_audio_driver_t* dev = (fluid_alsa_audio_driver_t*) d;
float* left;
@ -519,7 +473,7 @@ static void* fluid_alsa_audio_run_s16(void* d)
if ((left == NULL) || (right == NULL) || (buf == NULL)) {
FLUID_LOG(FLUID_ERR, "Out of memory.");
return NULL;
return;
}
handle[0] = left;
@ -590,8 +544,6 @@ static void* fluid_alsa_audio_run_s16(void* d)
FLUID_FREE(left);
FLUID_FREE(right);
FLUID_FREE(buf);
return NULL;
}
@ -617,9 +569,6 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
{
int i, err;
fluid_alsa_rawmidi_driver_t* dev;
pthread_attr_t attr;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int count;
struct pollfd *pfd = NULL;
@ -651,10 +600,6 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
fluid_settings_getint (settings, "midi.realtime-prio", &realtime_prio);
if (realtime_prio > 0)
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
/* get the device name. if none is specified, use the default device. */
fluid_settings_dupstr(settings, "midi.alsa.device", &device); /* ++ alloc device name */
@ -665,6 +610,8 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
goto error_recovery;
}
snd_rawmidi_nonblock(dev->rawmidi_in, 1);
/* get # of MIDI file descriptors */
count = snd_rawmidi_poll_descriptors_count(dev->rawmidi_in);
if (count > 0) { /* make sure there are some */
@ -687,58 +634,11 @@ new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
dev->status = FLUID_MIDI_READY;
/* create the midi thread */
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize midi thread attributes");
/* create the MIDI thread */
dev->thread = new_fluid_thread (fluid_alsa_midi_run, dev, realtime_prio, FALSE);
if (!dev->thread)
goto error_recovery;
}
/* Was: "use fifo scheduling. if it fails, use default scheduling." */
/* Now normal scheduling is used by default for the MIDI thread. The reason is,
* that fluidsynth works better with low latencies under heavy load, if only the
* audio thread is prioritized.
* With MIDI at ordinary priority, that could result in individual notes being played
* a bit late. On the other hand, if the audio thread is delayed, an audible dropout
* is the result.
* To reproduce this: Edirol UA-1 USB-MIDI interface, four buffers
* with 45 samples each (roughly 4 ms latency), ravewave soundfont. -MN
*/
/* Not so sure anymore. We're losing MIDI data, if we can't keep up with
* the speed it is generated. */
/* FLUID_LOG(FLUID_WARN, "Note: High-priority scheduling for the MIDI thread was intentionally disabled.");
sched=SCHED_OTHER;*/
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the MIDI input");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam (&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_alsa_midi_run, (void*) dev);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the MIDI input");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the midi thread.");
goto error_recovery;
}
}
break;
}
if (device) FLUID_FREE (device); /* -- free device name */
@ -764,19 +664,12 @@ delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p)
return FLUID_OK;
}
/* cancel the thread and wait for it before cleaning up */
dev->status = FLUID_MIDI_DONE;
/* cancel the thread and wait for it before cleaning up */
if (dev->thread) {
if (pthread_cancel(dev->thread)) {
FLUID_LOG(FLUID_ERR, "Failed to cancel the midi thread");
return FLUID_FAILED;
}
if (pthread_join(dev->thread, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to join the midi thread");
return FLUID_FAILED;
}
}
if (dev->thread)
fluid_thread_join (dev->thread);
if (dev->rawmidi_in) {
snd_rawmidi_close(dev->rawmidi_in);
}
@ -790,22 +683,12 @@ delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p)
/*
* fluid_alsa_midi_run
*/
void*
void
fluid_alsa_midi_run(void* d)
{
int n, i;
fluid_midi_event_t* evt;
fluid_alsa_rawmidi_driver_t* dev = (fluid_alsa_rawmidi_driver_t*) d;
/* make sure the other threads can cancel this thread any time */
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
pthread_exit(NULL);
}
if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
pthread_exit(NULL);
}
int n, i;
/* go into a loop until someone tells us to stop */
dev->status = FLUID_MIDI_LISTENING;
@ -833,7 +716,6 @@ fluid_alsa_midi_run(void* d)
}
}
}
pthread_exit(NULL);
}
/**************************************************************
@ -889,9 +771,6 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
{
int i, err;
fluid_alsa_seq_driver_t* dev;
pthread_attr_t attr;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int count;
struct pollfd *pfd = NULL;
@ -921,10 +800,6 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
fluid_settings_getint (settings, "midi.realtime-prio", &realtime_prio);
if (realtime_prio > 0)
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
/* get the device name. if none is specified, use the default device. */
if (fluid_settings_dupstr(settings, "midi.alsa_seq.device", &device) == 0) /* ++ alloc device name */
goto error_recovery;
@ -958,6 +833,8 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
goto error_recovery;
}
snd_seq_nonblock (dev->seq_handle, 1);
/* get # of MIDI file descriptors */
count = snd_seq_poll_descriptors_count(dev->seq_handle, POLLIN);
if (count > 0) { /* make sure there are some */
@ -1031,42 +908,8 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
dev->status = FLUID_MIDI_READY;
/* create the midi thread */
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize midi thread attributes");
goto error_recovery;
}
/* use fifo scheduling. if it fails, use default scheduling. */
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the MIDI input");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam (&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_alsa_seq_run, (void*) dev);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the MIDI input");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the midi thread.");
goto error_recovery;
}
}
break;
}
/* create the MIDI thread */
dev->thread = new_fluid_thread (fluid_alsa_seq_run, dev, realtime_prio, FALSE);
if (portname) FLUID_FREE (portname);
if (id) FLUID_FREE (id);
@ -1098,19 +941,12 @@ delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p)
return FLUID_OK;
}
/* cancel the thread and wait for it before cleaning up */
dev->status = FLUID_MIDI_DONE;
/* cancel the thread and wait for it before cleaning up */
if (dev->thread) {
if (pthread_cancel(dev->thread)) {
FLUID_LOG(FLUID_ERR, "Failed to cancel the midi thread");
return FLUID_FAILED;
}
if (pthread_join(dev->thread, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to join the midi thread");
return FLUID_FAILED;
}
}
if (dev->thread)
fluid_thread_join (dev->thread);
if (dev->seq_handle) {
snd_seq_close(dev->seq_handle);
}
@ -1124,7 +960,7 @@ delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p)
/*
* fluid_alsa_seq_run
*/
void*
void
fluid_alsa_seq_run(void* d)
{
int n, ev;
@ -1132,16 +968,6 @@ fluid_alsa_seq_run(void* d)
fluid_midi_event_t evt;
fluid_alsa_seq_driver_t* dev = (fluid_alsa_seq_driver_t*) d;
/* make sure the other threads can cancel this thread any time */
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
pthread_exit(NULL);
}
if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
pthread_exit(NULL);
}
/* go into a loop until someone tells us to stop */
dev->status = FLUID_MIDI_LISTENING;
while (dev->status == FLUID_MIDI_LISTENING) {
@ -1155,6 +981,8 @@ fluid_alsa_seq_run(void* d)
{
ev = snd_seq_event_input(dev->seq_handle, &seq_ev); /* read the events */
if (ev == -EAGAIN) break;
/* Negative value indicates an error, ignore interrupted system call
* (-EPERM) and input event buffer overrun (-ENOSPC) */
if (ev < 0)
@ -1226,7 +1054,6 @@ fluid_alsa_seq_run(void* d)
while (ev > 0);
} /* if poll() > 0 */
} /* while (dev->status == FLUID_MIDI_LISTENING) */
pthread_exit(NULL);
}
#endif /* #if ALSA_SUPPORT */

View file

@ -234,7 +234,7 @@ new_fluid_shell(fluid_settings_t* settings, fluid_cmd_handler_t* handler,
if (thread) {
shell->thread = new_fluid_thread((fluid_thread_func_t) fluid_shell_run, shell,
FLUID_THREAD_PRIO_NORMAL, 0, TRUE);
0, TRUE);
if (shell->thread == NULL) {
delete_fluid_shell(shell);
return NULL;
@ -1937,7 +1937,7 @@ new_fluid_client(fluid_server_t* server, fluid_settings_t* settings,
client->handler = handler;
client->thread = new_fluid_thread((fluid_thread_func_t) fluid_client_run, client,
FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
0, FALSE);
if (client->thread == NULL) {
fluid_socket_close(sock);

View file

@ -37,7 +37,6 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@ -56,7 +55,7 @@ typedef struct {
fluid_synth_t* synth;
fluid_audio_callback_t read;
void* buffer;
pthread_t thread;
fluid_thread_t *thread;
int cont;
int dspfd;
int buffer_size;
@ -74,14 +73,14 @@ int delete_fluid_oss_audio_driver(fluid_audio_driver_t* p);
/* local utilities */
static int fluid_oss_set_queue_size(fluid_oss_audio_driver_t* dev, int ss, int ch, int qs, int bs);
static void* fluid_oss_audio_run(void* d);
static void* fluid_oss_audio_run2(void* d);
static void fluid_oss_audio_run(void* d);
static void fluid_oss_audio_run2(void* d);
typedef struct {
fluid_midi_driver_t driver;
int fd;
pthread_t thread;
fluid_thread_t *thread;
int status;
unsigned char buffer[BUFFER_LENGTH];
fluid_midi_parser_t* parser;
@ -92,7 +91,7 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler, void* data);
int delete_fluid_oss_midi_driver(fluid_midi_driver_t* p);
int fluid_oss_midi_driver_status(fluid_midi_driver_t* p);
static void* fluid_oss_midi_run(void* d);
static void fluid_oss_midi_run(void* d);
void
@ -113,13 +112,9 @@ new_fluid_oss_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
int queuesize;
double sample_rate;
int periods, period_size;
int realtime_prio = 0;
char* devname = NULL;
int format;
pthread_attr_t attr;
int err;
int sched;
struct sched_param priority;
int realtime_prio = 0;
dev = FLUID_NEW(fluid_oss_audio_driver_t);
if (dev == NULL) {
@ -133,10 +128,6 @@ new_fluid_oss_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_getint (settings, "audio.realtime-prio", &realtime_prio);
if (realtime_prio > 0)
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
dev->dspfd = -1;
dev->synth = synth;
dev->callback = NULL;
@ -230,46 +221,11 @@ new_fluid_oss_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
goto error_recovery;
}
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
/* Create the audio thread */
dev->thread = new_fluid_thread (fluid_oss_audio_run, dev, realtime_prio, FALSE);
if (!dev->thread)
goto error_recovery;
}
/* the pthread_create man page explains that
pthread_attr_setschedpolicy returns an error if the user is not
permitted the set SCHED_FIFO. it seems however that no error is
returned but pthread_create fails instead. that's why i try to
create the thread twice in a while loop. */
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam (&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_oss_audio_run, (void*) dev);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
goto error_recovery;
}
}
break;
}
if (devname) FLUID_FREE (devname); /* -- free device name */
@ -291,12 +247,8 @@ new_fluid_oss_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func,
double sample_rate;
int periods, period_size;
char* devname = NULL;
int format;
pthread_attr_t attr;
int err;
int sched;
struct sched_param priority;
int realtime_prio = 0;
int format;
dev = FLUID_NEW(fluid_oss_audio_driver_t);
if (dev == NULL) {
@ -310,10 +262,6 @@ new_fluid_oss_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func,
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_getint (settings, "audio.realtime-prio", &realtime_prio);
if (realtime_prio > 0)
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
dev->dspfd = -1;
dev->synth = NULL;
dev->read = NULL;
@ -397,46 +345,11 @@ new_fluid_oss_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func,
goto error_recovery;
}
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
/* Create the audio thread */
dev->thread = new_fluid_thread (fluid_oss_audio_run2, dev, realtime_prio, FALSE);
if (!dev->thread)
goto error_recovery;
}
/* the pthread_create man page explains that
pthread_attr_setschedpolicy returns an error if the user is not
permitted the set SCHED_FIFO. it seems however that no error is
returned but pthread_create fails instead. that's why i try to
create the thread twice in a while loop. */
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam (&attr, &priority);
err = pthread_create(&dev->thread, &attr, fluid_oss_audio_run2, (void*) dev);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
goto error_recovery;
}
}
break;
}
if (devname) FLUID_FREE (devname); /* -- free device name */
@ -459,13 +372,12 @@ delete_fluid_oss_audio_driver(fluid_audio_driver_t* p)
if (dev == NULL) {
return FLUID_OK;
}
dev->cont = 0;
if (dev->thread) {
if (pthread_join(dev->thread, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to join the audio thread");
return FLUID_FAILED;
}
}
if (dev->thread)
fluid_thread_join (dev->thread);
if (dev->dspfd >= 0) {
close(dev->dspfd);
}
@ -525,7 +437,7 @@ fluid_oss_set_queue_size(fluid_oss_audio_driver_t* dev, int ss, int ch, int qs,
/*
* fluid_oss_audio_run
*/
void*
void
fluid_oss_audio_run(void* d)
{
fluid_oss_audio_driver_t* dev = (fluid_oss_audio_driver_t*) d;
@ -547,17 +459,13 @@ fluid_oss_audio_run(void* d)
}
FLUID_LOG(FLUID_DBG, "Audio thread finished");
pthread_exit(NULL);
return 0; /* not reached */
}
/*
* fluid_oss_audio_run
*/
void*
void
fluid_oss_audio_run2(void* d)
{
fluid_oss_audio_driver_t* dev = (fluid_oss_audio_driver_t*) d;
@ -586,10 +494,6 @@ fluid_oss_audio_run2(void* d)
}
FLUID_LOG(FLUID_DBG, "Audio thread finished");
pthread_exit(NULL);
return 0; /* not reached */
}
@ -605,11 +509,7 @@ fluid_midi_driver_t*
new_fluid_oss_midi_driver(fluid_settings_t* settings,
handle_midi_event_func_t handler, void* data)
{
int err;
fluid_oss_midi_driver_t* dev;
pthread_attr_t attr;
int sched;
struct sched_param priority;
int realtime_prio = 0;
char* device = NULL;
@ -653,10 +553,6 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
fluid_settings_getint (settings, "midi.realtime-prio", &realtime_prio);
if (realtime_prio > 0)
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
/* open the default hardware device. only use midi in. */
dev->fd = open(device, O_RDONLY, 0);
if (dev->fd < 0) {
@ -664,44 +560,20 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
goto error_recovery;
}
dev->status = FLUID_MIDI_READY;
/* create the midi thread */
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize midi thread attributes");
if (fcntl (dev->fd, F_SETFL, O_NONBLOCK) == -1)
{
FLUID_LOG(FLUID_ERR, "Failed to set OSS MIDI device to non-blocking: %s",
strerror (errno));
goto error_recovery;
}
/* use fifo scheduling. if it fails, use default scheduling. */
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the MIDI input");
if (sched == SCHED_FIFO) {
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam (&attr, &priority);
dev->status = FLUID_MIDI_READY;
err = pthread_create(&dev->thread, &attr, fluid_oss_midi_run, (void*) dev);
if (err) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the MIDI input");
if (sched == SCHED_FIFO) {
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the midi thread.");
goto error_recovery;
}
}
break;
}
/* create MIDI thread */
dev->thread = new_fluid_thread (fluid_oss_midi_run, dev, realtime_prio, FALSE);
if (!dev->thread)
goto error_recovery;
if (device) FLUID_FREE (device); /* ++ free device */
@ -719,7 +591,6 @@ new_fluid_oss_midi_driver(fluid_settings_t* settings,
int
delete_fluid_oss_midi_driver(fluid_midi_driver_t* p)
{
int err;
fluid_oss_midi_driver_t* dev;
dev = (fluid_oss_midi_driver_t*) p;
@ -727,20 +598,12 @@ delete_fluid_oss_midi_driver(fluid_midi_driver_t* p)
return FLUID_OK;
}
/* cancel the thread and wait for it before cleaning up */
dev->status = FLUID_MIDI_DONE;
/* cancel the thread and wait for it before cleaning up */
if (dev->thread) {
err = pthread_cancel(dev->thread);
if (err) {
FLUID_LOG(FLUID_ERR, "Failed to cancel the midi thread");
return FLUID_FAILED;
}
if (pthread_join(dev->thread, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to join the midi thread");
return FLUID_FAILED;
}
}
if (dev->thread)
fluid_thread_join (dev->thread);
if (dev->fd >= 0) {
close(dev->fd);
}
@ -754,34 +617,42 @@ delete_fluid_oss_midi_driver(fluid_midi_driver_t* p)
/*
* fluid_oss_midi_run
*/
void*
void
fluid_oss_midi_run(void* d)
{
int n, i;
fluid_midi_event_t* evt;
fluid_oss_midi_driver_t* dev = (fluid_oss_midi_driver_t*) d;
/* make sure the other threads can cancel this thread any time */
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
pthread_exit(NULL);
}
if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
pthread_exit(NULL);
}
fluid_midi_event_t* evt;
struct pollfd fds;
int n, i;
/* go into a loop until someone tells us to stop */
dev->status = FLUID_MIDI_LISTENING;
fds.fd = dev->fd;
fds.events = POLLIN;
fds.revents = 0;
while (dev->status == FLUID_MIDI_LISTENING) {
n = poll (&fds, 1, 100);
if (n == 0) continue;
if (n < 0)
{
FLUID_LOG(FLUID_ERR, "Error waiting for MIDI input: %s", strerror (errno));
break;
}
/* read new data */
n = read(dev->fd, dev->buffer, BUFFER_LENGTH);
if (n == -EAGAIN) continue;
if (n < 0) {
perror("read");
FLUID_LOG(FLUID_ERR, "Failed to read the midi input");
dev->status = FLUID_MIDI_DONE;
break;
}
/* let the parser convert the data into events */
@ -792,9 +663,7 @@ fluid_oss_midi_run(void* d)
(*dev->driver.handler)(dev->driver.data, evt);
}
}
}
pthread_exit(NULL);
}
int

View file

@ -28,7 +28,6 @@
#include "fluid_adriver.h"
#include "fluid_settings.h"
#include <pthread.h>
#include "config.h"
#include <pulse/simple.h>
@ -45,7 +44,7 @@ typedef struct {
fluid_audio_func_t callback;
void* data;
int buffer_size;
pthread_t thread;
fluid_thread_t *thread;
int cont;
} fluid_pulse_audio_driver_t;
@ -56,8 +55,8 @@ fluid_audio_driver_t* new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
fluid_audio_func_t func, void* data);
int delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p);
void fluid_pulse_audio_driver_settings(fluid_settings_t* settings);
static void* fluid_pulse_audio_run(void* d);
static void* fluid_pulse_audio_run2(void* d);
static void fluid_pulse_audio_run(void* d);
static void fluid_pulse_audio_run2(void* d);
void fluid_pulse_audio_driver_settings(fluid_settings_t* settings)
@ -85,10 +84,7 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
int period_size, period_bytes;
char *server = NULL;
char *device = NULL;
pthread_attr_t attr;
struct sched_param priority;
int realtime_prio = 0;
int sched;
int err;
dev = FLUID_NEW(fluid_pulse_audio_driver_t);
@ -106,10 +102,6 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
fluid_settings_dupstr(settings, "audio.pulseaudio.device", &device); /* ++ alloc device string */
fluid_settings_getint (settings, "audio.realtime-prio", &realtime_prio);
if (realtime_prio > 0)
sched = SCHED_FIFO;
else sched = SCHED_OTHER;
if (server && strcmp (server, "default") == 0)
{
FLUID_FREE (server); /* -- free server string */
@ -153,48 +145,10 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
FLUID_LOG(FLUID_INFO, "Using PulseAudio driver");
/* Create the audio thread */
if (pthread_attr_init(&attr)) {
FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
dev->thread = new_fluid_thread (func ? fluid_pulse_audio_run2 : fluid_pulse_audio_run,
dev, realtime_prio, FALSE);
if (!dev->thread)
goto error_recovery;
}
/* The pthread_create man page explains that
pthread_attr_setschedpolicy returns an error if the user is not
permitted the set SCHED_FIFO. It seems however that no error is
returned but pthread_create fails instead. That's why I try to
create the thread twice in a while loop. */
while (1) {
err = pthread_attr_setschedpolicy(&attr, sched);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
goto error_recovery;
}
}
/* SCHED_FIFO will not be active without setting the priority */
priority.sched_priority = realtime_prio;
pthread_attr_setschedparam(&attr, &priority);
err = pthread_create(&dev->thread, &attr,
func ? fluid_pulse_audio_run2 : fluid_pulse_audio_run, (void*) dev);
if (err) {
if (sched == SCHED_FIFO) {
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
sched = SCHED_OTHER;
continue;
} else {
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
goto error_recovery;
}
}
break;
}
if (server) FLUID_FREE (server); /* -- free server string */
if (device) FLUID_FREE (device); /* -- free device string */
@ -218,12 +172,8 @@ int delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p)
dev->cont = 0;
if (dev->thread) {
if (pthread_join(dev->thread, NULL)) {
FLUID_LOG(FLUID_ERR, "Failed to join the audio thread");
return FLUID_FAILED;
}
}
if (dev->thread)
fluid_thread_join (dev->thread);
if (dev->pa_handle)
pa_simple_free(dev->pa_handle);
@ -234,7 +184,8 @@ int delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p)
}
/* Thread without audio callback, more efficient */
static void* fluid_pulse_audio_run(void* d)
static void
fluid_pulse_audio_run(void* d)
{
fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
float *buf;
@ -243,12 +194,13 @@ static void* fluid_pulse_audio_run(void* d)
buffer_size = dev->buffer_size;
/* FIXME - Probably shouldn't alloc in run() */
buf = FLUID_ARRAY(float, buffer_size * 2);
if (buf == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory.");
return NULL;
return;
}
while (dev->cont)
@ -264,11 +216,10 @@ static void* fluid_pulse_audio_run(void* d)
} /* while (dev->cont) */
FLUID_FREE(buf);
return NULL;
}
static void* fluid_pulse_audio_run2(void* d)
static void
fluid_pulse_audio_run2(void* d)
{
fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
fluid_synth_t *synth = (fluid_synth_t *)(dev->data);
@ -280,6 +231,7 @@ static void* fluid_pulse_audio_run2(void* d)
buffer_size = dev->buffer_size;
/* FIXME - Probably shouldn't alloc in run() */
left = FLUID_ARRAY(float, buffer_size);
right = FLUID_ARRAY(float, buffer_size);
buf = FLUID_ARRAY(float, buffer_size * 2);
@ -287,7 +239,7 @@ static void* fluid_pulse_audio_run2(void* d)
if (left == NULL || right == NULL || buf == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory.");
return NULL;
return;
}
handle[0] = left;
@ -315,6 +267,4 @@ static void* fluid_pulse_audio_run2(void* d)
FLUID_FREE(left);
FLUID_FREE(right);
FLUID_FREE(buf);
return NULL;
}

View file

@ -735,7 +735,7 @@ new_fluid_synth(fluid_settings_t *settings)
/* Initialize multi-core variables if multiple cores enabled */
if (synth->cores > 1)
{
int prio_level = 0, prio;
int prio_level = 0;
synth->core_mutex = new_fluid_cond_mutex ();
synth->core_cond = new_fluid_cond ();
@ -763,14 +763,10 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint (synth->settings, "audio.realtime-prio", &prio_level);
if (prio_level > 0)
prio = FLUID_THREAD_PRIO_HIGH;
else prio = FLUID_THREAD_PRIO_NORMAL;
for (i = 0; i < synth->cores - 1; i++)
{
synth->core_threads[i] = new_fluid_thread (fluid_synth_core_thread_func,
synth, prio, prio_level, FALSE);
synth, prio_level, FALSE);
if (!synth->core_threads[i])
FLUID_LOG(FLUID_ERR, "Failed to create a synthesis core thread");
}

View file

@ -390,9 +390,9 @@ fluid_utime (void)
#if defined(WIN32) /* Windoze specific stuff */
void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
fluid_thread_self_set_prio (int prio_level)
{
if (prio == FLUID_THREAD_PRIO_HIGH)
if (prio_level > 0)
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
@ -400,20 +400,20 @@ fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
#elif defined(__OS2__) /* OS/2 specific stuff */
void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
fluid_thread_self_set_prio (int prio_level)
{
if (prio == FLUID_THREAD_PRIO_HIGH)
if (prio_level > 0)
DosSetPriority (PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
}
#else /* POSIX stuff.. Nice POSIX.. Good POSIX. */
void
fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level)
fluid_thread_self_set_prio (int prio_level)
{
struct sched_param priority;
if (prio == FLUID_THREAD_PRIO_HIGH)
if (prio_level > 0)
{
priority.sched_priority = prio_level;
@ -564,7 +564,7 @@ fluid_thread_high_prio (gpointer data)
{
fluid_thread_info_t *info = data;
fluid_thread_self_set_prio (FLUID_THREAD_PRIO_HIGH, info->prio_level);
fluid_thread_self_set_prio (info->prio_level);
info->func (info->data);
FLUID_FREE (info);
@ -576,14 +576,13 @@ fluid_thread_high_prio (gpointer data)
* Create a new thread.
* @param func Function to execute in new thread context
* @param data User defined data to pass to func
* @param prio Priority class
* @param prio_level Priority level (used only for high priority on Posix currently, 1-99)
* @param prio_level Priority level. If greater than 0 then high priority scheduling will
* be used, with the given priority level (used by pthreads only). 0 uses normal scheduling.
* @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
* @return New thread pointer or NULL on error
*/
fluid_thread_t *
new_fluid_thread (fluid_thread_func_t func, void *data,
fluid_thread_prio_t prio, int prio_level, int detach)
new_fluid_thread (fluid_thread_func_t func, void *data, int prio_level, int detach)
{
GThread *thread;
fluid_thread_info_t *info;
@ -596,7 +595,7 @@ new_fluid_thread (fluid_thread_func_t func, void *data,
* but what can we do *and* remain backwards compatible? */
if (!g_thread_supported ()) g_thread_init (NULL);
if (prio == FLUID_THREAD_PRIO_HIGH)
if (prio_level > 0)
{
info = FLUID_NEW (fluid_thread_info_t);
@ -707,8 +706,7 @@ new_fluid_timer (int msec, fluid_timer_callback_t callback, void* data,
if (new_thread)
{
timer->thread = new_fluid_thread (fluid_timer_run, timer, high_priority
? FLUID_THREAD_PRIO_HIGH : FLUID_THREAD_PRIO_NORMAL,
FLUID_SYS_TIMER_HIGH_PRIO_LEVEL, FALSE);
? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
if (!timer->thread)
{
FLUID_FREE (timer);
@ -1010,7 +1008,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
server_socket->cont = 1;
server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket,
FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
0, FALSE);
if (server_socket->thread == NULL) {
FLUID_FREE(server_socket);
fluid_socket_close(sock);
@ -1160,7 +1158,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
server_socket->cont = 1;
server_socket->thread = new_fluid_thread(fluid_server_socket_run, server_socket,
FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
0, FALSE);
if (server_socket->thread == NULL)
{
FLUID_FREE (server_socket);

View file

@ -226,23 +226,14 @@ typedef GStaticPrivate fluid_private_t;
typedef GThread fluid_thread_t;
typedef void (*fluid_thread_func_t)(void* data);
/**
* Thread priorities.
*/
typedef enum
{
FLUID_THREAD_PRIO_NORMAL, /**< Normal thread priority */
FLUID_THREAD_PRIO_HIGH /**< High priority thread */
} fluid_thread_prio_t;
#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */
#define fluid_thread_id_t GThread * /* Data type for a thread ID */
#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */
fluid_thread_t* new_fluid_thread(fluid_thread_func_t func, void *data,
fluid_thread_prio_t prio, int prio_level, int detach);
int prio_level, int detach);
void delete_fluid_thread(fluid_thread_t* thread);
void fluid_thread_self_set_prio (fluid_thread_prio_t prio, int prio_level);
void fluid_thread_self_set_prio (int prio_level);
int fluid_thread_join(fluid_thread_t* thread);
/* Sockets and I/O */

View file

@ -223,7 +223,7 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
/* Create thread which processes re-adding SYSEX buffers */
dev->sysExAddThread = new_fluid_thread (fluid_winmidi_add_sysex_thread,
dev, FLUID_THREAD_PRIO_NORMAL, 0, FALSE);
dev, 0, FALSE);
if (!dev->sysExAddThread)
{
FLUID_LOG(FLUID_ERR, "Failed to create SYSEX buffer processing thread");