/* * Author: Marc A. Lehmann * License: public domain, or where this is not possible/at your option, * CC0 (https://creativecommons.org/publicdomain/zero/1.0/) */ #ifndef XSTHREADPOOL_H #define XSTHREADPOOL_H #define XSTHREADPOOL_VERSION 1 #define XSTHREADPOOL_MAGIC1 0x03417854 #define XSTHREADPOOL_MAGIC2 0x809a7b39 struct xsthreadpool_request_type { U32 magic1; int req_data_size; /* this should fill in the request structure, which has undefined contents */ /* by parsing the nitem perl scalars at *items */ /* typically, this does some error checking and then serialises the items into *req_data */ /* on error, it should simply croak */ /* this callback must not block (in the Coro sense) */ /* can be 0 if no preparation is needed */ void (*xstpreq_prepare) (pTHX_ void *req_struct, SV **items, int nitems); /* this is called in another thread and should do the actual work */ /* it MUST NOT access any perl data structures */ /* but can freely read and write *req_data */ /* this is the only callback that cannot be 0 */ void (*xstpreq_execute) (void *req_data); /* this should push any result values to be passed to the rfesult callback */ /* onto the perl stack */ /* it can be 0 if the request never has any results */ void (*xstpreq_finish) (pTHX_ void *req_data); /* this should destroy/free the request data */ /* it can be called at any time from perl */ /* specifically, both before or after the request has executed */ /* it can be 0 if no cleanup is required */ void (*xstpreq_destroy) (pTHX_ void *req); U32 magic2; }; /* * define a new xs threadpool request type/handler. * stash is the package the name should be put in, * e.g. gv_stashpvn (PACKAGE, sizeof (PACKAGE), TRUE) * or, in an xs function or BOOT:, you can use "CvSTASH (cv)" * name is the perl function name inside the stash * datatype should be the request data type, which is passed to prepare/exec/finish/free * it should not be too large, try not to make it larger than, say, 200 bytes. */ #define XSTHREADPOOL_REQUEST_TYPE(stash,name,datatype,prepare,execute,finish,destroy) \ do { \ /* these assignments exist only for type checking, and will likely be optimised out */ \ void (*xstpreq_prepare)(datatype *, SV **, int) = (prepare); \ void (*xstpreq_execute)(datatype *) = (execute); \ void (*xstpreq_finish )(datatype *) = (finish ); \ void (*xstpreq_destroy)(datatype *) = (destroy); \ /* this does the actual registration */ \ static const struct xsthreadpool_request_type xsthreadpool_request_type = { \ XSTHREADPOOL_MAGIC1, \ sizeof (datatype), \ (void (*)(void *, SV **, int))(prepare), \ (void (*)(void *))(execute), \ (void (*)(void *))(finish), \ (void (*)(void *))(destroy), \ XSTHREADPOOL_MAGIC2 \ }; \ SV *request_type_sv = newSVpvn ((void *)&xsthreadpool_request_type, \ sizeof (xsthreadpool_request_type)); \ SvREADONLY_on (request_type_sv); \ newCONSTSUB ((stash), (name), request_type_sv); \ } while (0) #endif