Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

address Fauck crash on exit #16

Merged
merged 1 commit into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions source/projects/chuck/core/chuck_dl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,16 @@ Chuck_DL_MainThreadHook * CK_DLL_CALL ck_create_main_thread_hook( Chuck_DL_Query
return new Chuck_DL_MainThreadHook( hook, quit, bindle, query->carrier() );
}

//-----------------------------------------------------------------------------
// name: ck_register_callback_on_shutdown() | 1.5.2.5 (ge) added
// desc: register a callback function to be called on host exit
// (both natural or SIGINT)
//-----------------------------------------------------------------------------
void CK_DLL_CALL ck_register_callback_on_shutdown( Chuck_DL_Query * query, f_callback_on_shutdown cb, void * bindle )
{
// register
query->vm()->register_callback_on_shutdown( cb, bindle );
}

//-----------------------------------------------------------------------------
// name: ck_register_shreds_watcher()
Expand Down Expand Up @@ -1351,6 +1361,7 @@ Chuck_DL_Query::Chuck_DL_Query( Chuck_Carrier * carrier, Chuck_DLL * dll )
create_main_thread_hook = ck_create_main_thread_hook;
register_shreds_watcher = ck_register_shreds_watcher; // 1.5.1.5 (ge & andrew)
unregister_shreds_watcher = ck_unregister_shreds_watcher; // 1.5.1.5 (ge & andrew)
register_callback_on_shutdown = ck_register_callback_on_shutdown; // 1.5.2.5 (ge)
m_carrier = carrier;
dll_ref = dll; // 1.5.1.3 (ge) added

Expand Down
14 changes: 13 additions & 1 deletion source/projects/chuck/core/chuck_dl.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
#define CK_DLL_VERSION_MAJOR (10)
// minor API version: revisions
// minor API version of chuck must >= API version of chugin
#define CK_DLL_VERSION_MINOR (1)
#define CK_DLL_VERSION_MINOR (2)
#define CK_DLL_VERSION_MAKE(maj,min) ((t_CKUINT)(((maj) << 16) | (min)))
#define CK_DLL_VERSION_GETMAJOR(v) (((v) >> 16) & 0xFFFF)
#define CK_DLL_VERSION_GETMINOR(v) ((v) & 0xFFFF)
Expand Down Expand Up @@ -340,6 +340,8 @@ typedef t_CKBOOL (CK_DLL_CALL * f_tock)( Chuck_Object * SELF, Chuck_UAna * UANA,
typedef t_CKBOOL (CK_DLL_CALL * f_mainthreadhook)( void * bindle );
// "main thread" quit (stop running hook)
typedef t_CKBOOL (CK_DLL_CALL * f_mainthreadquit)( void * bindle );
// callback function, called on host shutdown
typedef void (CK_DLL_CALL * f_callback_on_shutdown)( void * bindle );
// shreds watcher callback
typedef void (CK_DLL_CALL * f_shreds_watcher)( Chuck_VM_Shred * SHRED, t_CKINT CODE, t_CKINT PARAM, Chuck_VM * VM, void * BINDLE );
// type instantiation callback
Expand Down Expand Up @@ -414,6 +416,8 @@ typedef void (CK_DLL_CALL * f_add_ugen_funcf_auto_num_channels)( Chuck_DL_Query
typedef t_CKBOOL (CK_DLL_CALL * f_end_class)( Chuck_DL_Query * query );
// create main thread hook- used for executing a "hook" function in the main thread of a primary chuck instance
typedef Chuck_DL_MainThreadHook * (CK_DLL_CALL * f_create_main_thread_hook)( Chuck_DL_Query * query, f_mainthreadhook hook, f_mainthreadquit quit, void * bindle );
// register a callback to be called on host shutdown, e.g., for chugin cleanup
typedef void (CK_DLL_CALL * f_register_callback_on_shutdown)( Chuck_DL_Query * query, f_callback_on_shutdown cb, void * bindle );
// register a callback function to receive notification from the VM about shreds (add, remove, etc.)
typedef void (CK_DLL_CALL * f_register_shreds_watcher)( Chuck_DL_Query * query, f_shreds_watcher cb, t_CKUINT options, void * bindle );
// unregister a shreds notification callback
Expand Down Expand Up @@ -589,6 +593,14 @@ struct Chuck_DL_Query
// -------------
f_create_main_thread_hook create_main_thread_hook;

public:
// -------------
// register a function to be run on host shutdown; this can be used
// for chugin cleanup when the host (chuck, miniAudicle, etc.) exits
// including on SIGINT (ctrl-c termination) | added 1.5.2.5 (ge)
// -------------
f_register_callback_on_shutdown register_callback_on_shutdown;

public:
// -------------
// register callback to be invoked by chuck host at various
Expand Down
49 changes: 49 additions & 0 deletions source/projects/chuck/core/chuck_vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ t_CKBOOL Chuck_VM::shutdown()
// set state
m_init = FALSE;

// notify registered callbacks we are shutting down | 1.5.2.5 (ge) added
notify_callbacks_on_shutdown();

// relockdown (added 1.3.6.0)
// REFACTOR-2017: TODO -- remove once made per-VM
Chuck_VM_Object::lock_all();
Expand Down Expand Up @@ -1431,6 +1434,52 @@ Chuck_VM_Shred * Chuck_VM::get_current_shred() const



//-----------------------------------------------------------------------------
// name: register_callback_on_shutdown()
// cesc: register a callback to be called on VM shutdown | 1.5.2.5 (ge) added
//-----------------------------------------------------------------------------
void Chuck_VM::register_callback_on_shutdown( f_callback_on_shutdown cb, void * bindle )
{
// check
if( !cb ) return;

// ensure no duplicates
list<Chuck_VM_Callback_On_Shutdown>::iterator it = std::find( m_callbacks_on_shutdown.begin(),
m_callbacks_on_shutdown.end(), cb );
// add if not already preset
if( it == m_callbacks_on_shutdown.end() )
{
// append
m_callbacks_on_shutdown.push_back( Chuck_VM_Callback_On_Shutdown(cb, bindle) );
}
}




//-----------------------------------------------------------------------------
// name: notify_callbacks_on_shutdown()
// desc: notify callbacks on VM shutdown | 1.5.2.5 (ge) added
//-----------------------------------------------------------------------------
void Chuck_VM::notify_callbacks_on_shutdown()
{
// the function to call eventually
f_callback_on_shutdown f = NULL;
// iterator
list<Chuck_VM_Callback_On_Shutdown>::iterator it;
// iterate
for( it = m_callbacks_on_shutdown.begin(); it != m_callbacks_on_shutdown.end(); it++ )
{
// the function
f = (*it).cb;
// call it with user data
f( (*it).userdata );
}
}




//-----------------------------------------------------------------------------
// name: notify_watchers()
// desc: notify watchers for a particular subscription | 1.5.1.5
Expand Down
39 changes: 39 additions & 0 deletions source/projects/chuck/core/chuck_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,33 @@ struct Chuck_VM_Status : public Chuck_Object



//-----------------------------------------------------------------------------
// name: struct Chuck_VM_Callback_On_Shutdown
// desc: an entry for a callback to be called on VM shutdown
//-----------------------------------------------------------------------------
struct Chuck_VM_Callback_On_Shutdown
{
// function pointer to call
f_callback_on_shutdown cb;
// user data
void * userdata;

// constructor
Chuck_VM_Callback_On_Shutdown( f_callback_on_shutdown f = NULL, void * data = NULL )
: cb(f), userdata(data) { }

// copy constructor
Chuck_VM_Callback_On_Shutdown( const Chuck_VM_Callback_On_Shutdown & other )
: cb(other.cb), userdata(other.userdata) { }

// ==
bool operator ==( const Chuck_VM_Callback_On_Shutdown & other )
{ return this->cb == other.cb; }
};




//-----------------------------------------------------------------------------
// name: struct Chuck_VM_Shreduler
// desc: a ChucK shreduler shredules shreds
Expand Down Expand Up @@ -657,6 +684,14 @@ struct Chuck_VM : public Chuck_Object
// remove shreds watcher callback | 1.5.1.5
void remove_watcher( f_shreds_watcher cb );

public:
// register a callback to be called on VM shutdown | 1.5.2.5 (ge) added
void register_callback_on_shutdown( f_callback_on_shutdown cb, void * bindle );

protected:
// notify callbacks on VM shutdown | 1.5.2.5 (ge) added
void notify_callbacks_on_shutdown();

//-----------------------------------------------------------------------------
// data
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -733,6 +768,10 @@ struct Chuck_VM : public Chuck_Object
std::list<Chuck_VM_Shreds_Watcher> m_shreds_watchers_remove;
std::list<Chuck_VM_Shreds_Watcher> m_shreds_watchers_suspend;
std::list<Chuck_VM_Shreds_Watcher> m_shreds_watchers_activate;

protected:
// 1.5.2.5 (ge) on major VM events callbacks
std::list<Chuck_VM_Callback_On_Shutdown> m_callbacks_on_shutdown;
};


Expand Down
88 changes: 86 additions & 2 deletions source/projects/chugins/Fauck/Faust.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ std::string getPathToFaustLibraries() {
#ifdef NOBUNDLE
const char* myDLLPath = getMyDLLPath();
std::filesystem::path p = std::filesystem::path(myDLLPath).parent_path().parent_path() / "faust" ;
std::cout << "path: " << p << std::endl;
std::cout << "faust library path: " << p << std::endl;
return p.string();
#else
// look for faustlibraries inside the bundle
Expand Down Expand Up @@ -851,14 +851,89 @@ class Faust
};


//-----------------------------------------------------------------------------
// name: class Faucktory | v0.2.0 added (ge)
// desc: a fauck factory for globally keep track of open Faust instances
// used as a date structure of "smart pointers" to ensure each is
// closed properly; currently, for example, an abrupt closing in
// ChucK (e.g., ctrl-c) or application closing (miniAudicle, Max, etc.)
// does not cleanup live objects, leading to crashes-on-exit like:
// ```
// libc++abi: terminating due to uncaught exception of type
// std::__1::system_error: recursive_mutex lock failed: Invalid argument
// zsh: abort
// ```
//-----------------------------------------------------------------------------
class Faucktory
{
public:
// destructor | to be called on exit
~Faucktory() { cleanup(); }

// add a Faust object to track
void add( Faust * fck )
{
// insert
faucks[fck] = fck;
}
// remove a Faust object
void remove( Faust * fck )
{
// count
if( faucks.count(fck) == 0 ) return;
// remove from map
faucks.erase( fck );
}
// cleanup all tracked Faust objects
void cleanup()
{
std::map<Faust *, Faust *>::iterator it;
for( it = faucks.begin(); it != faucks.end(); it++ )
{
// get the pointer
Faust * fck = it->second;
// clean it up
if( fck ) fck->clear();
}
// clear the map entries
faucks.clear();
}

public: // singleton API
static Faucktory * instance()
{
// instance
if( !o_faucktory ) { o_faucktory = new Faucktory(); }
return o_faucktory;
}

protected:
std::map<Faust *, Faust *> faucks;

private: // enforce singleton
Faucktory() { }
static Faucktory * o_faucktory;
};

// static global faucktory | v0.2.0 (ge) added
Faucktory * Faucktory::o_faucktory = NULL;

// callback to be called on host shutdown (so we can clean up)
static void cb_on_host_shutdown( void * bindle )
{
// explcitly call cleanup (in case of SIGINT, global object dtors doesn't run)
Faucktory::instance()->cleanup();
}


//-----------------------------------------------------------------------------
// info function: ChucK calls this when loading/probing the chugin
// NOTE: please customize these info fields below; they will be used for
// chugins loading, probing, and package management and documentation
//-----------------------------------------------------------------------------
CK_DLL_INFO( Faust )
{
QUERY->setinfo( QUERY, CHUGIN_INFO_CHUGIN_VERSION, "v0.0.1" );
QUERY->setinfo( QUERY, CHUGIN_INFO_CHUGIN_VERSION, "v0.2.0" );
QUERY->setinfo( QUERY, CHUGIN_INFO_AUTHORS, "Ge Wang, Romain Michon, David Braun" );
QUERY->setinfo( QUERY, CHUGIN_INFO_DESCRIPTION, "A chugin which dynamically compiles and executes FAUST code via LLVM." );
QUERY->setinfo( QUERY, CHUGIN_INFO_URL, "https://github.com/ccrma/fauck" );
Expand All @@ -876,6 +951,9 @@ CK_DLL_QUERY( Faust )
// hmm, don't change this...
QUERY->setname(QUERY, "Faust");

// register a callback to be called upon host shutdown (so we can clean up)
QUERY->register_callback_on_shutdown(QUERY, cb_on_host_shutdown, NULL);

// begin the class definition
// can change the second argument to extend a different ChucK class
QUERY->begin_class(QUERY, "Faust", "UGen");
Expand Down Expand Up @@ -1006,6 +1084,9 @@ CK_DLL_CTOR(faust_ctor)

// store the pointer in the ChucK object member
OBJ_MEMBER_INT(SELF, faust_data_offset) = (t_CKINT) faust_obj;

// add to global registry
Faucktory::instance()->add( faust_obj );
}

// implementation for the destructor
Expand All @@ -1014,6 +1095,9 @@ CK_DLL_DTOR(faust_dtor)
// get our c++ class pointer
Faust * faust_obj = (Faust *) OBJ_MEMBER_INT(SELF, faust_data_offset);

// remove from global registry
Faucktory::instance()->remove( faust_obj );

// clean up (this macro tests for NULL, deletes, and zeros out the variable)
CK_SAFE_DELETE( faust_obj );
// set the data field to 0
Expand Down
16 changes: 14 additions & 2 deletions source/projects/chugins/chuck/include/chugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
// 1.5.0.0 (ge) | moved to chuck.h for at-a-glance visibility
// 1.5.2.0 (ge) | moved to chuck_def.h for chugins headers streamlining
//-----------------------------------------------------------------------------
#define CHUCK_VERSION_STRING "1.5.2.4 (chai)"
#define CHUCK_VERSION_STRING "1.5.2.5-dev (chai)"
//-----------------------------------------------------------------------------


Expand Down Expand Up @@ -1158,7 +1158,7 @@ struct a_Program_ { a_Section section; a_Program next; uint32_t line; uint32_t w
#define CK_DLL_VERSION_MAJOR (10)
// minor API version: revisions
// minor API version of chuck must >= API version of chugin
#define CK_DLL_VERSION_MINOR (1)
#define CK_DLL_VERSION_MINOR (2)
#define CK_DLL_VERSION_MAKE(maj,min) ((t_CKUINT)(((maj) << 16) | (min)))
#define CK_DLL_VERSION_GETMAJOR(v) (((v) >> 16) & 0xFFFF)
#define CK_DLL_VERSION_GETMINOR(v) ((v) & 0xFFFF)
Expand Down Expand Up @@ -1435,6 +1435,8 @@ typedef t_CKBOOL (CK_DLL_CALL * f_tock)( Chuck_Object * SELF, Chuck_UAna * UANA,
typedef t_CKBOOL (CK_DLL_CALL * f_mainthreadhook)( void * bindle );
// "main thread" quit (stop running hook)
typedef t_CKBOOL (CK_DLL_CALL * f_mainthreadquit)( void * bindle );
// callback function, called on host shutdown
typedef void (CK_DLL_CALL * f_callback_on_shutdown)( void * bindle );
// shreds watcher callback
typedef void (CK_DLL_CALL * f_shreds_watcher)( Chuck_VM_Shred * SHRED, t_CKINT CODE, t_CKINT PARAM, Chuck_VM * VM, void * BINDLE );
// type instantiation callback
Expand Down Expand Up @@ -1509,6 +1511,8 @@ typedef void (CK_DLL_CALL * f_add_ugen_funcf_auto_num_channels)( Chuck_DL_Query
typedef t_CKBOOL (CK_DLL_CALL * f_end_class)( Chuck_DL_Query * query );
// create main thread hook- used for executing a "hook" function in the main thread of a primary chuck instance
typedef Chuck_DL_MainThreadHook * (CK_DLL_CALL * f_create_main_thread_hook)( Chuck_DL_Query * query, f_mainthreadhook hook, f_mainthreadquit quit, void * bindle );
// register a callback to be called on host shutdown, e.g., for chugin cleanup
typedef void (CK_DLL_CALL * f_register_callback_on_shutdown)( Chuck_DL_Query * query, f_callback_on_shutdown cb, void * bindle );
// register a callback function to receive notification from the VM about shreds (add, remove, etc.)
typedef void (CK_DLL_CALL * f_register_shreds_watcher)( Chuck_DL_Query * query, f_shreds_watcher cb, t_CKUINT options, void * bindle );
// unregister a shreds notification callback
Expand Down Expand Up @@ -1684,6 +1688,14 @@ struct Chuck_DL_Query
// -------------
f_create_main_thread_hook create_main_thread_hook;

public:
// -------------
// register a function to be run on host shutdown; this can be used
// for chugin cleanup on the host (chuck, miniAudicle, etc.) exits
// added 1.5.2.5 (ge)
// -------------
f_register_callback_on_shutdown register_callback_on_shutdown;

public:
// -------------
// register callback to be invoked by chuck host at various
Expand Down