diff options
| author | David Robillard <d@drobilla.net> | 2012-02-13 01:01:38 +0000 | 
|---|---|---|
| committer | David Robillard <d@drobilla.net> | 2012-02-13 01:01:38 +0000 | 
| commit | 806dd3218ab67efcc68e25bfe3a68fddfec029b6 (patch) | |
| tree | c8cdc9b356d57fcaf7169afa0e8e9cf7b7ec4e50 /plugins | |
| parent | 651bc82e5d45c534115e85f568319feab95c38f6 (diff) | |
| download | lv2-806dd3218ab67efcc68e25bfe3a68fddfec029b6.tar.xz | |
Use portable thread implementation.
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/eg-sampler.lv2/sampler.c | 52 | ||||
| -rw-r--r-- | plugins/eg-sampler.lv2/zix/sem.h | 32 | ||||
| -rw-r--r-- | plugins/eg-sampler.lv2/zix/thread.h | 133 | 
3 files changed, 182 insertions, 35 deletions
| diff --git a/plugins/eg-sampler.lv2/sampler.c b/plugins/eg-sampler.lv2/sampler.c index 8ee2c05..c6bf30c 100644 --- a/plugins/eg-sampler.lv2/sampler.c +++ b/plugins/eg-sampler.lv2/sampler.c @@ -37,8 +37,6 @@  #include <stdlib.h>  #include <string.h> -#include <pthread.h> -  #include <sndfile.h>  #include "lv2/lv2plug.in/ns/ext/atom/atom-helpers.h" @@ -48,6 +46,7 @@  #include "lv2/lv2plug.in/ns/lv2core/lv2.h"  #include "zix/sem.h" +#include "zix/thread.h"  #include "./uris.h" @@ -70,10 +69,14 @@ typedef struct {  	/* Features */  	LV2_URID_Map* map; +	/* Worker thread */ +	ZixThread worker_thread; +	ZixSem    signal; +	bool      exit; +  	/* Sample */  	SampleFile* samp;  	SampleFile* pending_samp; -	ZixSem      signal;  	int         pending_sample_ready;  	/* Ports */ @@ -92,11 +95,9 @@ typedef struct {  	} uris;  	/* Playback state */ -	bool       play;  	sf_count_t frame; +	bool       play; -	/* File loading */ -	pthread_t worker_thread;  } Sampler;  static void @@ -142,8 +143,7 @@ worker_thread_main(void* arg)  {  	Sampler* plugin = (Sampler*)arg; -	/* TODO: This thread never exits cleanly */ -	while (true) { +	while (!plugin->exit) {  		/* Wait for run() to signal that we need to load a sample */  		zix_sem_wait(&plugin->signal); @@ -155,21 +155,6 @@ worker_thread_main(void* arg)  }  static void -cleanup(LV2_Handle instance) -{ -	Sampler* plugin = (Sampler*)instance; -	pthread_cancel(plugin->worker_thread); -	pthread_join(plugin->worker_thread, 0); -	zix_sem_destroy(&plugin->signal); - -	free(plugin->samp->data); -	free(plugin->pending_samp->data); -	free(plugin->samp); -	free(plugin->pending_samp); -	free(instance); -} - -static void  connect_port(LV2_Handle instance,               uint32_t   port,               void*      data) @@ -216,7 +201,9 @@ instantiate(const LV2_Descriptor*     descriptor,  	}  	/* Create worker thread */ -	if (pthread_create(&plugin->worker_thread, 0, worker_thread_main, plugin)) { +	plugin->exit = false; +	if (zix_thread_create( +		    &plugin->worker_thread, 1024, worker_thread_main, plugin)) {  		fprintf(stderr, "Could not initialize worker thread.\n");  		goto fail;  	} @@ -258,6 +245,23 @@ fail:  }  static void +cleanup(LV2_Handle instance) +{ +	Sampler* plugin = (Sampler*)instance; + +	plugin->exit = true; +	zix_sem_post(&plugin->signal); +	zix_thread_join(plugin->worker_thread, 0); +	zix_sem_destroy(&plugin->signal); + +	free(plugin->samp->data); +	free(plugin->pending_samp->data); +	free(plugin->samp); +	free(plugin->pending_samp); +	free(instance); +} + +static void  run(LV2_Handle instance,      uint32_t   sample_count)  { diff --git a/plugins/eg-sampler.lv2/zix/sem.h b/plugins/eg-sampler.lv2/zix/sem.h index 98117c8..0b2bbb1 100644 --- a/plugins/eg-sampler.lv2/zix/sem.h +++ b/plugins/eg-sampler.lv2/zix/sem.h @@ -23,6 +23,7 @@  #    include <windows.h>  #else  #    include <semaphore.h> +#    include <errno.h>  #endif  #include "zix/common.h" @@ -80,7 +81,7 @@ zix_sem_post(ZixSem* sem);     Wait until count is > 0, then decrement.     Obviously not realtime safe.  */ -static inline void +static inline ZixStatus  zix_sem_wait(ZixSem* sem);  /** @@ -120,10 +121,13 @@ zix_sem_post(ZixSem* sem)  	semaphore_signal(sem->sem);  } -static inline void +static inline ZixStatus  zix_sem_wait(ZixSem* sem)  { -	semaphore_wait(sem->sem); +	if (semaphore_wait(sem->sem) != KERN_SUCCESS) { +		return ZIX_STATUS_ERROR; +	} +	return ZIX_STATUS_SUCCESS;  }  static inline bool @@ -158,10 +162,13 @@ zix_sem_post(ZixSem* sem)  	ReleaseSemaphore(sem->sem, 1, NULL);  } -static inline void +static inline ZixStatus  zix_sem_wait(ZixSem* sem)  { -	WaitForSingleObject(sem->sem, INFINITE); +	if (WaitForSingleObject(sem->sem, INFINITE) != WAIT_OBJECT_0) { +		return ZIX_STATUS_ERROR; +	} +	return ZIX_STATUS_SUCCESS;  }  static inline bool @@ -195,14 +202,17 @@ zix_sem_post(ZixSem* sem)  	sem_post(&sem->sem);  } -static inline void +static inline ZixStatus  zix_sem_wait(ZixSem* sem)  { -	/* Note that sem_wait always returns 0 in practice, except in -	   gdb (at least), where it returns nonzero, so the while is -	   necessary (and is the correct/safe solution in any case). -	*/ -	while (sem_wait(&sem->sem) != 0) {} +	while (sem_wait(&sem->sem)) { +		if (errno != EINTR) { +			return ZIX_STATUS_ERROR; +		} +		/* Otherwise, interrupted, so try again. */ +	} + +	return ZIX_STATUS_SUCCESS;  }  static inline bool diff --git a/plugins/eg-sampler.lv2/zix/thread.h b/plugins/eg-sampler.lv2/zix/thread.h new file mode 100644 index 0000000..ff5a727 --- /dev/null +++ b/plugins/eg-sampler.lv2/zix/thread.h @@ -0,0 +1,133 @@ +/* +  Copyright 2012 David Robillard <http://drobilla.net> + +  Permission to use, copy, modify, and/or distribute this software for any +  purpose with or without fee is hereby granted, provided that the above +  copyright notice and this permission notice appear in all copies. + +  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#ifndef ZIX_THREAD_H +#define ZIX_THREAD_H + +#ifdef _WIN32 +#    include <windows.h> +#else +#    include <errno.h> +#    include <pthread.h> +#endif + +#include "zix/common.h" + +#ifdef __cplusplus +extern "C" { +#else +#    include <stdbool.h> +#endif + +/** +   @addtogroup zix +   @{ +   @name Thread +   @{ +*/ + +#ifdef _WIN32 +typedef HANDLE ZixThread; +#else +typedef pthread_t ZixThread; +#endif + +/** +   Initialize @c thread to a new thread. + +   The thread will immediately be launched, calling @c function with @c arg +   as the only parameter. +*/ +static inline ZixStatus +zix_thread_create(ZixThread* thread, +                  size_t     stack_size, +                  void*      (*function)(void*), +                  void*      arg); + +/** +   Join @c thread (block until @c thread exits). +*/ +static inline ZixStatus +zix_thread_join(ZixThread thread, void** retval); + +#ifdef _WIN32 + +static inline ZixStatus +zix_thread_create(ZixThread* thread, +                  size_t     stack_size, +                  void*      (*function)(void*), +                  void*      arg) +{ +	*thread = CreateThread(NULL, stack_size, +	                       (LPTHREAD_START_ROUTINE)function, arg, +	                       0, NULL); +	return *thread ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; +} + +static inline ZixStatus +zix_thread_join(ZixThread thread, void** retval) +{ +	return WaitForSingleObject(thread, INFINITE) +		? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; +} + +#else  /* !defined(_WIN32) */ + +static inline ZixStatus +zix_thread_create(ZixThread* thread, +                  size_t     stack_size, +                  void*      (*function)(void*), +                  void*      arg) +{ +	pthread_attr_t attr; +	pthread_attr_init(&attr); +	pthread_attr_setstacksize(&attr, stack_size); + +	const int ret = pthread_create(thread, NULL, function, arg); +	pthread_attr_destroy(&attr); + +	if (ret == EAGAIN) { +		return ZIX_STATUS_NO_MEM; +	} else if (ret == EINVAL) { +		return ZIX_STATUS_BAD_ARG; +	} else if (ret == EPERM) { +		return ZIX_STATUS_BAD_PERMS; +	} else if (ret) { +		return ZIX_STATUS_ERROR; +	} + +	return ZIX_STATUS_SUCCESS; +} + +static inline ZixStatus +zix_thread_join(ZixThread thread, void** retval) +{ +	return pthread_join(thread, retval) +		? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS; +} + +#endif + +/** +   @} +   @} +*/ + +#ifdef __cplusplus +}  /* extern "C" */ +#endif + +#endif  /* ZIX_THREAD_H */ |