| 1 |
root |
1.1 |
/* |
| 2 |
|
|
* Author: Marc A. Lehmann <xsthreadpool@schmorp.de> |
| 3 |
|
|
* License: public domain, or where this is not possible/at your option, |
| 4 |
|
|
* CC0 (https://creativecommons.org/publicdomain/zero/1.0/) |
| 5 |
|
|
*/ |
| 6 |
|
|
#ifndef XSTHREADPOOL_H |
| 7 |
|
|
#define XSTHREADPOOL_H |
| 8 |
|
|
|
| 9 |
|
|
#define XSTHREADPOOL_VERSION 1 |
| 10 |
|
|
#define XSTHREADPOOL_MAGIC1 0x03417854 |
| 11 |
|
|
#define XSTHREADPOOL_MAGIC2 0x809a7b39 |
| 12 |
|
|
|
| 13 |
|
|
struct xsthreadpool_request_type |
| 14 |
|
|
{ |
| 15 |
|
|
U32 magic1; |
| 16 |
|
|
int req_data_size; |
| 17 |
|
|
|
| 18 |
|
|
/* this should fill in the request structure, which has undefined contents */ |
| 19 |
|
|
/* by parsing the nitem perl scalars at *items */ |
| 20 |
|
|
/* typically, this does some error checking and then serialises the items into *req_data */ |
| 21 |
|
|
/* on error, it should simply croak */ |
| 22 |
|
|
/* this callback must not block (in the Coro sense) */ |
| 23 |
|
|
/* can be 0 if no preparation is needed */ |
| 24 |
|
|
void (*xstpreq_prepare) (pTHX_ void *req_struct, SV **items, int nitems); |
| 25 |
|
|
|
| 26 |
|
|
/* this is called in another thread and should do the actual work */ |
| 27 |
|
|
/* it MUST NOT access any perl data structures */ |
| 28 |
|
|
/* but can freely read and write *req_data */ |
| 29 |
|
|
/* this is the only callback that cannot be 0 */ |
| 30 |
|
|
void (*xstpreq_execute) (void *req_data); |
| 31 |
|
|
|
| 32 |
|
|
/* this should push any result values to be passed to the rfesult callback */ |
| 33 |
|
|
/* onto the perl stack */ |
| 34 |
|
|
/* it can be 0 if the request never has any results */ |
| 35 |
|
|
void (*xstpreq_finish) (pTHX_ void *req_data); |
| 36 |
|
|
|
| 37 |
|
|
/* this should destroy/free the request data */ |
| 38 |
|
|
/* it can be called at any time from perl */ |
| 39 |
|
|
/* specifically, both before or after the request has executed */ |
| 40 |
|
|
/* it can be 0 if no cleanup is required */ |
| 41 |
|
|
void (*xstpreq_destroy) (pTHX_ void *req); |
| 42 |
|
|
|
| 43 |
|
|
U32 magic2; |
| 44 |
|
|
}; |
| 45 |
|
|
|
| 46 |
|
|
/* |
| 47 |
|
|
* define a new xs threadpool request type/handler. |
| 48 |
|
|
* stash is the package the name should be put in, |
| 49 |
|
|
* e.g. gv_stashpvn (PACKAGE, sizeof (PACKAGE), TRUE) |
| 50 |
|
|
* or, in an xs function or BOOT:, you can use "CvSTASH (cv)" |
| 51 |
|
|
* name is the perl function name inside the stash |
| 52 |
|
|
* datatype should be the request data type, which is passed to prepare/exec/finish/free |
| 53 |
|
|
* it should not be too large, try not to make it larger than, say, 200 bytes. |
| 54 |
|
|
*/ |
| 55 |
|
|
#define XSTHREADPOOL_REQUEST_TYPE(stash,name,datatype,prepare,execute,finish,destroy) \ |
| 56 |
|
|
do { \ |
| 57 |
|
|
/* these assignments exist only for type checking, and will likely be optimised out */ \ |
| 58 |
|
|
void (*xstpreq_prepare)(datatype *, SV **, int) = (prepare); \ |
| 59 |
|
|
void (*xstpreq_execute)(datatype *) = (execute); \ |
| 60 |
|
|
void (*xstpreq_finish )(datatype *) = (finish ); \ |
| 61 |
|
|
void (*xstpreq_destroy)(datatype *) = (destroy); \ |
| 62 |
|
|
/* this does the actual registration */ \ |
| 63 |
|
|
static const struct xsthreadpool_request_type xsthreadpool_request_type = { \ |
| 64 |
|
|
XSTHREADPOOL_MAGIC1, \ |
| 65 |
|
|
sizeof (datatype), \ |
| 66 |
|
|
(void (*)(void *, SV **, int))(prepare), \ |
| 67 |
|
|
(void (*)(void *))(execute), \ |
| 68 |
|
|
(void (*)(void *))(finish), \ |
| 69 |
|
|
(void (*)(void *))(destroy), \ |
| 70 |
|
|
XSTHREADPOOL_MAGIC2 \ |
| 71 |
|
|
}; \ |
| 72 |
|
|
SV *request_type_sv = newSVpvn ((void *)&xsthreadpool_request_type, \ |
| 73 |
|
|
sizeof (xsthreadpool_request_type)); \ |
| 74 |
|
|
SvREADONLY_on (request_type_sv); \ |
| 75 |
|
|
newCONSTSUB ((stash), (name), request_type_sv); \ |
| 76 |
|
|
} while (0) |
| 77 |
|
|
|
| 78 |
|
|
#endif |
| 79 |
|
|
|