1 /* 2 * Copyright (c) 2012 Joyent, Inc. All rights reserved. 3 */ 4 5 #ifndef _V8PLUS_GLUE_H 6 #define _V8PLUS_GLUE_H 7 8 #include <stdarg.h> 9 #include <libnvpair.h> 10 #include "v8plus_errno.h" 11 12 #ifdef __cplusplus 13 extern "C" { 14 #endif /* __cplusplus */ 15 16 #define __UNUSED __attribute__((__unused__)) 17 18 #define V8PLUS_ARG_F_NOEXTRA 0x01 19 20 #define V8PLUS_ERRMSG_LEN 512 21 #define V8PLUS_JSF_COOKIE ".__v8plus_jsfunc_cookie" 22 23 typedef enum v8plus_type { 24 V8PLUS_TYPE_NONE = 0, /* N/A */ 25 V8PLUS_TYPE_STRING, /* char * */ 26 V8PLUS_TYPE_NUMBER, /* double */ 27 V8PLUS_TYPE_BOOLEAN, /* boolean_t */ 28 V8PLUS_TYPE_JSFUNC, /* v8plus_jsfunc_t */ 29 V8PLUS_TYPE_OBJECT, /* nvlist_t * */ 30 V8PLUS_TYPE_NULL, /* -- */ 31 V8PLUS_TYPE_UNDEFINED, /* -- */ 32 V8PLUS_TYPE_INVALID, /* data_type_t */ 33 V8PLUS_TYPE_ANY, /* nvpair_t * */ 34 V8PLUS_TYPE_STRNUMBER64, /* uint64_t */ 35 V8PLUS_TYPE_INL_OBJECT /* ... */ 36 } v8plus_type_t; 37 38 typedef uint64_t v8plus_jsfunc_t; 39 40 /* 41 * C constructor, destructor, and method prototypes. See README.md. 42 */ 43 typedef nvlist_t *(*v8plus_c_ctor_f)(const nvlist_t *, void **); 44 typedef nvlist_t *(*v8plus_c_static_f)(const nvlist_t *); 45 typedef nvlist_t *(*v8plus_c_method_f)(void *, const nvlist_t *); 46 typedef void (*v8plus_c_dtor_f)(void *); 47 48 typedef struct v8plus_method_descr { 49 const char *md_name; 50 v8plus_c_method_f md_c_func; 51 } v8plus_method_descr_t; 52 53 typedef struct v8plus_static_descr { 54 const char *sd_name; 55 v8plus_c_static_f sd_c_func; 56 } v8plus_static_descr_t; 57 58 extern __thread v8plus_errno_t _v8plus_errno; 59 extern __thread char _v8plus_errmsg[V8PLUS_ERRMSG_LEN]; 60 61 /* 62 * Set the errno and message, indicating an error. The code and 63 * printf-formatted message, if one is given, will be used in constructing 64 * an exception to be thrown in JavaScript if your method later returns NULL 65 * or an nvlist with an "err" member. 66 */ 67 extern nvlist_t *v8plus_verror(v8plus_errno_t, const char *, va_list); 68 extern nvlist_t *v8plus_error(v8plus_errno_t, const char *, ...); 69 70 /* 71 * Suicide. It's always an option. Try to avoid using this as it's not 72 * very nice to kill the entire node process; if at all possible we need 73 * to throw a JavaScript exception instead. 74 */ 75 extern void v8plus_panic(const char *, ...) __PRINTFLIKE(1) __NORETURN; 76 77 /* 78 * As above, this convenience function sets the error code and message based 79 * on the nvlist-generated error code in its first argument. The second 80 * argument, which may be NULL, should contain the name of the member on 81 * which the error occurred. 82 */ 83 extern nvlist_t *v8plus_nverr(int, const char *); 84 85 /* 86 * Similarly, for system errors. Not all possible errno values are handled. 87 */ 88 extern nvlist_t *v8plus_syserr(int, const char *, ...); 89 90 /* 91 * Clear the errno and message. This is needed only when one wishes to return 92 * NULL from a C method whose return type is effectively void. The idiom is 93 * 94 * return (v8plus_void()); 95 */ 96 extern nvlist_t *v8plus_void(void); 97 98 /* 99 * Find the named V8 function in the nvlist. Analogous to other lookup 100 * routines; see libnvpair(3lib), with an important exception: the 101 * nvlist_lookup_v8plus_jsfunc() and nvpair_value_v8plus_jsfunc() functions 102 * place a hold on the underlying function object, which must be released by C 103 * code when it is no longer needed. See the documentation to understand how 104 * this works. The add routine is of very limited utility because there is no 105 * mechanism for creating a JS function from C. It can however be used to 106 * return a function (or object containing one, etc.) from a deferred 107 * completion routine in which a JS function has been invoked that returned 108 * such a thing to us. 109 */ 110 extern int nvlist_lookup_v8plus_jsfunc(const nvlist_t *, const char *, 111 v8plus_jsfunc_t *); 112 extern int nvpair_value_v8plus_jsfunc(const nvpair_t *, v8plus_jsfunc_t *); 113 extern void v8plus_jsfunc_hold(v8plus_jsfunc_t); 114 extern void v8plus_jsfunc_rele(v8plus_jsfunc_t); 115 extern void v8plus_jsfunc_rele_direct(v8plus_jsfunc_t); 116 117 /* 118 * Place or release a hold on the V8 representation of the specified C object. 119 * This is rarely necessary; v8plus_defer() performs this action for you, but 120 * other asynchronous mechanisms may require it. If you are returning from 121 * a method call but have stashed a reference to the object somewhere and are 122 * not calling v8plus_defer(), you must call this first. Holds and releases 123 * must be balanced. Use of the object within a thread after releasing is a 124 * bug. 125 */ 126 extern void v8plus_obj_hold(const void *); 127 extern void v8plus_obj_rele(const void *); 128 extern void v8plus_obj_rele_direct(const void *); 129 130 /* 131 * Convenience functions for dealing with JS arguments. 132 */ 133 extern v8plus_type_t v8plus_typeof(const nvpair_t *); 134 extern int v8plus_args(const nvlist_t *, uint_t, v8plus_type_t t, ...); 135 extern nvlist_t *v8plus_obj(v8plus_type_t, ...); 136 extern int v8plus_obj_setprops(nvlist_t *, v8plus_type_t, ...); 137 138 /* 139 * Perform a background, possibly blocking and/or expensive, task. First, 140 * the worker function will be enqueued for execution on another thread; its 141 * first argument is a pointer to the C object on which to operate, and the 142 * second is arbitrary per-call context, arguments, etc. defined by the caller. 143 * When that worker function has completed execution, the completion function 144 * will be invoked in the main thread. Its arguments are the C object, the 145 * original context pointer, and the return value from the worker function. 146 * See the documentation for a typical use case. 147 */ 148 typedef void *(*v8plus_worker_f)(void *, void *); 149 typedef void (*v8plus_completion_f)(void *, void *, void *); 150 151 extern void v8plus_defer(void *, void *, v8plus_worker_f, v8plus_completion_f); 152 153 /* 154 * Call an opaque JavaScript function from C. The caller is responsible for 155 * freeing the returned list. The first argument is not const because it is 156 * possible for the JS code to modify the function represented by the cookie. 157 */ 158 extern nvlist_t *v8plus_call(v8plus_jsfunc_t, const nvlist_t *); 159 extern nvlist_t *v8plus_call_direct(v8plus_jsfunc_t, const nvlist_t *); 160 161 /* 162 * Call the named JavaScript function in the context of the JS object 163 * represented by the native object. Calling and return conventions are the 164 * same as for the C interfaces; i.e., the nvlist will be converted into JS 165 * objects and the return value or exception will be in the "res" or "err" 166 * members of the nvlist that is returned, respectively. If an internal 167 * error occurs, NULL is returned and _v8plus_errno set accordingly. The 168 * results of calling a method implemented in C via this interface are 169 * undefined. 170 * 171 * These methods can be used in concert with JS code to emit events 172 * asynchronously; see the documentation. 173 * 174 * Note: As JavaScript functions must be called from the event loop thread, 175 * v8plus_method_call() contains logic to determine whether we are in the 176 * correct context or not. If we are running on some other thread we will 177 * queue the request and sleep, waiting for the event loop thread to make the 178 * call. In the simple case, where we are already in the correct thread, 179 * we make the call directly. v8plus_method_call_direct() assumes we are 180 * on the correct thread and always makes the call directly. 181 */ 182 extern nvlist_t *v8plus_method_call(void *, const char *, const nvlist_t *); 183 extern nvlist_t *v8plus_method_call_direct(void *, const char *, 184 const nvlist_t *); 185 186 /* 187 * These functions allow the consumer to hold the V8 event loop open for 188 * potential input from other threads. If your process blocks in another 189 * thread, e.g. an event subscription thread, you must signal to v8plus 190 * that the event loop should remain active. Calls to v8plus_eventloop_hold() 191 * and v8plus_eventloop_rele() should be balanced. It is safe to call 192 * v8plus_eventloop_rele() from outside the event loop thread. 193 * 194 * Note: Holds obtained via v8plus_obj_hold() and v8plus_jsfunc_hold() will 195 * also automatically hold the event loop, removing the need to use this 196 * interface explicitly. 197 */ 198 extern void v8plus_eventloop_hold(void); 199 extern void v8plus_eventloop_rele(void); 200 extern void v8plus_eventloop_rele_direct(void); 201 202 /* 203 * These methods are analogous to strerror(3c) and similar functions; they 204 * translate among error names, codes, and default messages. There is 205 * normally little need for these functions in C methods, as everything 206 * necessary to construct a JavaScript exception is done by v8+, but these 207 * may be useful in the construction of supplementary exception decorations 208 * for debugging purposes. 209 */ 210 extern const char *v8plus_strerror(v8plus_errno_t); 211 extern const char *v8plus_errname(v8plus_errno_t); 212 extern const char *v8plus_excptype(v8plus_errno_t); 213 214 /* 215 * Provided by C code. See README.md. 216 */ 217 extern const v8plus_c_ctor_f v8plus_ctor; 218 extern const v8plus_c_dtor_f v8plus_dtor; 219 extern const char *v8plus_js_factory_name; 220 extern const char *v8plus_js_class_name; 221 extern const v8plus_method_descr_t v8plus_methods[]; 222 extern const uint_t v8plus_method_count; 223 extern const v8plus_static_descr_t v8plus_static_methods[]; 224 extern const uint_t v8plus_static_method_count; 225 226 /* 227 * Private methods. 228 */ 229 extern boolean_t v8plus_in_event_thread(void); 230 extern void v8plus_crossthread_init(void); 231 232 #ifdef __cplusplus 233 } 234 #endif /* __cplusplus */ 235 236 #endif /* _V8PLUS_GLUE_H */