/* * gvl_wrappers.h - Wrapper functions for locking/unlocking the Ruby GVL * * These are some obscure preprocessor directives that allow to generate * drop-in replacement wrapper functions in a declarative manner. * These wrapper functions ensure that ruby's GVL is released on each * function call and reacquired at the end of the call or in callbacks. * This way blocking functions calls don't block concurrent ruby threads. * * The wrapper of each function is prefixed by "gvl_". * * Use "gcc -E" to retrieve the generated code. */ #ifndef __gvl_wrappers_h #define __gvl_wrappers_h #include #ifdef RUBY_EXTCONF_H # include RUBY_EXTCONF_H #endif #ifndef HAVE_PQSETCHUNKEDROWSMODE typedef struct pg_cancel_conn PGcancelConn; #endif #define DEFINE_PARAM_LIST1(type, name) \ name, #define DEFINE_PARAM_LIST2(type, name) \ p->params.name, #define DEFINE_PARAM_LIST3(type, name) \ type name, #define DEFINE_PARAM_DECL(type, name) \ type name; #define DEFINE_GVL_WRAPPER_STRUCT(name, when_non_void, rettype, lastparamtype, lastparamname) \ struct gvl_wrapper_##name##_params { \ struct { \ FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_DECL) \ lastparamtype lastparamname; \ } params; \ when_non_void( rettype retval; ) \ }; #define DEFINE_GVL_SKELETON(name, when_non_void, rettype, lastparamtype, lastparamname) \ static void * gvl_##name##_skeleton( void *data ){ \ struct gvl_wrapper_##name##_params *p = (struct gvl_wrapper_##name##_params*)data; \ when_non_void( p->retval = ) \ name( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST2) p->params.lastparamname ); \ return NULL; \ } #ifdef ENABLE_GVL_UNLOCK #define DEFINE_GVL_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \ struct gvl_wrapper_##name##_params params = { \ {FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname}, when_non_void((rettype)0) \ }; \ rb_thread_call_without_gvl(gvl_##name##_skeleton, ¶ms, RUBY_UBF_IO, 0); \ when_non_void( return params.retval; ) \ } #else #define DEFINE_GVL_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \ when_non_void( return ) \ name( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname ); \ } #endif #define DEFINE_GVL_STUB_DECL(name, when_non_void, rettype, lastparamtype, lastparamname) \ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname); #define DEFINE_GVLCB_SKELETON(name, when_non_void, rettype, lastparamtype, lastparamname) \ static void * gvl_##name##_skeleton( void *data ){ \ struct gvl_wrapper_##name##_params *p = (struct gvl_wrapper_##name##_params*)data; \ when_non_void( p->retval = ) \ name( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST2) p->params.lastparamname ); \ return NULL; \ } #ifdef ENABLE_GVL_UNLOCK #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \ struct gvl_wrapper_##name##_params params = { \ {FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname}, when_non_void((rettype)0) \ }; \ rb_thread_call_with_gvl(gvl_##name##_skeleton, ¶ms); \ when_non_void( return params.retval; ) \ } #else #define DEFINE_GVLCB_STUB(name, when_non_void, rettype, lastparamtype, lastparamname) \ rettype gvl_##name(FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST3) lastparamtype lastparamname){ \ when_non_void( return ) \ name( FOR_EACH_PARAM_OF_##name(DEFINE_PARAM_LIST1) lastparamname ); \ } #endif #define GVL_TYPE_VOID(string) #define GVL_TYPE_NONVOID(string) string /* * Definitions of blocking functions and their parameters */ #define FOR_EACH_PARAM_OF_PQconnectdb(param) #define FOR_EACH_PARAM_OF_PQconnectStart(param) #define FOR_EACH_PARAM_OF_PQconnectPoll(param) #define FOR_EACH_PARAM_OF_PQreset(param) #define FOR_EACH_PARAM_OF_PQresetStart(param) #define FOR_EACH_PARAM_OF_PQresetPoll(param) #define FOR_EACH_PARAM_OF_PQping(param) #define FOR_EACH_PARAM_OF_PQexec(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQexecParams(param) \ param(PGconn *, conn) \ param(const char *, command) \ param(int, nParams) \ param(const Oid *, paramTypes) \ param(const char * const *, paramValues) \ param(const int *, paramLengths) \ param(const int *, paramFormats) #define FOR_EACH_PARAM_OF_PQexecPrepared(param) \ param(PGconn *, conn) \ param(const char *, stmtName) \ param(int, nParams) \ param(const char * const *, paramValues) \ param(const int *, paramLengths) \ param(const int *, paramFormats) #define FOR_EACH_PARAM_OF_PQprepare(param) \ param(PGconn *, conn) \ param(const char *, stmtName) \ param(const char *, query) \ param(int, nParams) #define FOR_EACH_PARAM_OF_PQdescribePrepared(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQdescribePortal(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQclosePrepared(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQclosePortal(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQgetResult(param) #define FOR_EACH_PARAM_OF_PQputCopyData(param) \ param(PGconn *, conn) \ param(const char *, buffer) #define FOR_EACH_PARAM_OF_PQputCopyEnd(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQgetCopyData(param) \ param(PGconn *, conn) \ param(char **, buffer) #define FOR_EACH_PARAM_OF_PQnotifies(param) #define FOR_EACH_PARAM_OF_PQsendQuery(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQsendQueryParams(param) \ param(PGconn *, conn) \ param(const char *, command) \ param(int, nParams) \ param(const Oid *, paramTypes) \ param(const char *const *, paramValues) \ param(const int *, paramLengths) \ param(const int *, paramFormats) #define FOR_EACH_PARAM_OF_PQsendPrepare(param) \ param(PGconn *, conn) \ param(const char *, stmtName) \ param(const char *, query) \ param(int, nParams) #define FOR_EACH_PARAM_OF_PQsendQueryPrepared(param) \ param(PGconn *, conn) \ param(const char *, stmtName) \ param(int, nParams) \ param(const char *const *, paramValues) \ param(const int *, paramLengths) \ param(const int *, paramFormats) #define FOR_EACH_PARAM_OF_PQsendDescribePrepared(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQsendDescribePortal(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQsendClosePrepared(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQsendClosePortal(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQpipelineSync(param) #define FOR_EACH_PARAM_OF_PQsendPipelineSync(param) #define FOR_EACH_PARAM_OF_PQsetClientEncoding(param) \ param(PGconn *, conn) #define FOR_EACH_PARAM_OF_PQisBusy(param) #define FOR_EACH_PARAM_OF_PQcancelBlocking(param) #define FOR_EACH_PARAM_OF_PQcancelStart(param) #define FOR_EACH_PARAM_OF_PQcancelPoll(param) #define FOR_EACH_PARAM_OF_PQencryptPasswordConn(param) \ param(PGconn *, conn) \ param(const char *, passwd) \ param(const char *, user) #define FOR_EACH_PARAM_OF_PQcancel(param) \ param(PGcancel *, cancel) \ param(char *, errbuf) /* function( name, void_or_nonvoid, returntype, lastparamtype, lastparamname ) */ #define FOR_EACH_BLOCKING_FUNCTION(function) \ function(PQconnectdb, GVL_TYPE_NONVOID, PGconn *, const char *, conninfo) \ function(PQconnectStart, GVL_TYPE_NONVOID, PGconn *, const char *, conninfo) \ function(PQconnectPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGconn *, conn) \ function(PQreset, GVL_TYPE_VOID, void, PGconn *, conn) \ function(PQresetStart, GVL_TYPE_NONVOID, int, PGconn *, conn) \ function(PQresetPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGconn *, conn) \ function(PQping, GVL_TYPE_NONVOID, PGPing, const char *, conninfo) \ function(PQexec, GVL_TYPE_NONVOID, PGresult *, const char *, command) \ function(PQexecParams, GVL_TYPE_NONVOID, PGresult *, int, resultFormat) \ function(PQexecPrepared, GVL_TYPE_NONVOID, PGresult *, int, resultFormat) \ function(PQprepare, GVL_TYPE_NONVOID, PGresult *, const Oid *, paramTypes) \ function(PQdescribePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \ function(PQdescribePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \ function(PQclosePrepared, GVL_TYPE_NONVOID, PGresult *, const char *, stmtName) \ function(PQclosePortal, GVL_TYPE_NONVOID, PGresult *, const char *, portalName) \ function(PQgetResult, GVL_TYPE_NONVOID, PGresult *, PGconn *, conn) \ function(PQputCopyData, GVL_TYPE_NONVOID, int, int, nbytes) \ function(PQputCopyEnd, GVL_TYPE_NONVOID, int, const char *, errormsg) \ function(PQgetCopyData, GVL_TYPE_NONVOID, int, int, async) \ function(PQnotifies, GVL_TYPE_NONVOID, PGnotify *, PGconn *, conn) \ function(PQsendQuery, GVL_TYPE_NONVOID, int, const char *, query) \ function(PQsendQueryParams, GVL_TYPE_NONVOID, int, int, resultFormat) \ function(PQsendPrepare, GVL_TYPE_NONVOID, int, const Oid *, paramTypes) \ function(PQsendQueryPrepared, GVL_TYPE_NONVOID, int, int, resultFormat) \ function(PQsendDescribePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \ function(PQsendDescribePortal, GVL_TYPE_NONVOID, int, const char *, portal) \ function(PQsendClosePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \ function(PQsendClosePortal, GVL_TYPE_NONVOID, int, const char *, portal) \ function(PQpipelineSync, GVL_TYPE_NONVOID, int, PGconn *, conn) \ function(PQsendPipelineSync, GVL_TYPE_NONVOID, int, PGconn *, conn) \ function(PQsetClientEncoding, GVL_TYPE_NONVOID, int, const char *, encoding) \ function(PQisBusy, GVL_TYPE_NONVOID, int, PGconn *, conn) \ function(PQcancelBlocking, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \ function(PQcancelStart, GVL_TYPE_NONVOID, int, PGcancelConn *, conn) \ function(PQcancelPoll, GVL_TYPE_NONVOID, PostgresPollingStatusType, PGcancelConn *, conn) \ function(PQencryptPasswordConn, GVL_TYPE_NONVOID, char *, const char *, algorithm) \ function(PQcancel, GVL_TYPE_NONVOID, int, int, errbufsize); FOR_EACH_BLOCKING_FUNCTION( DEFINE_GVL_STUB_DECL ); /* * Definitions of callback functions and their parameters */ #define FOR_EACH_PARAM_OF_notice_processor_proxy(param) \ param(void *, arg) #define FOR_EACH_PARAM_OF_notice_receiver_proxy(param) \ param(void *, arg) /* function( name, void_or_nonvoid, returntype, lastparamtype, lastparamname ) */ #define FOR_EACH_CALLBACK_FUNCTION(function) \ function(notice_processor_proxy, GVL_TYPE_VOID, void, const char *, message) \ function(notice_receiver_proxy, GVL_TYPE_VOID, void, const PGresult *, result) \ FOR_EACH_CALLBACK_FUNCTION( DEFINE_GVL_STUB_DECL ); #endif /* end __gvl_wrappers_h */