1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <assert.h> 5 #include <fcntl.h> 6 #include <errno.h> 7 #include <unistd.h> 8 #include <pthread.h> 9 10 #include <libnvpair.h> 11 12 #include "v8plus_glue.h" 13 14 typedef struct lockfd_args { 15 v8plus_jsfunc_t lfa_cb; 16 int lfa_fd; 17 struct flock lfa_flock; 18 boolean_t lfa_run_sync; 19 } lockfd_args_t; 20 21 /* 22 * Worker thread for blocking fcntl() calls: 23 */ 24 static void * 25 lockfd_thread(void *arg) 26 { 27 lockfd_args_t *lfa = arg; 28 nvlist_t *ap; 29 int ret, en = 0; 30 char *errmsg = ""; 31 32 errno = 0; 33 if ((ret = fcntl(lfa->lfa_fd, F_SETLKW, &lfa->lfa_flock)) == -1) { 34 errmsg = strerror(en); 35 } 36 37 /* 38 * Call back into JS: 39 */ 40 ap = v8plus_obj( 41 V8PLUS_TYPE_NUMBER, "0", (double) ret, 42 V8PLUS_TYPE_NUMBER, "1", (double) en, 43 V8PLUS_TYPE_STRING, "2", errmsg, 44 V8PLUS_TYPE_NONE); 45 (void) v8plus_call(lfa->lfa_cb, ap); 46 nvlist_free(ap); 47 48 if (!lfa->lfa_run_sync) { 49 /* 50 * Release our callback, held from the ititial call: 51 */ 52 v8plus_jsfunc_rele(lfa->lfa_cb); 53 } 54 55 free(lfa); 56 57 return (NULL); 58 } 59 60 /* 61 * Primary entrypoint from Javascript: 62 */ 63 static nvlist_t * 64 lockfd_lockfd(const nvlist_t *ap) 65 { 66 lockfd_args_t *lfa = calloc(1, sizeof (*lfa)); 67 pthread_t newthr; 68 double double_fd; 69 char *type; 70 71 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA, 72 V8PLUS_TYPE_NUMBER, &double_fd, 73 V8PLUS_TYPE_STRING, &type, 74 V8PLUS_TYPE_BOOLEAN, &lfa->lfa_run_sync, 75 V8PLUS_TYPE_JSFUNC, &lfa->lfa_cb, 76 V8PLUS_TYPE_NONE) != 0) { 77 free(lfa); 78 return (v8plus_error(V8PLUSERR_BADARG, "bad args")); 79 } 80 lfa->lfa_fd = double_fd; 81 82 /* 83 * Configure the flock struct for locking: 84 */ 85 if (strcmp(type, "read") == 0) { 86 lfa->lfa_flock.l_type = F_RDLCK; 87 } else if (strcmp(type, "write") == 0) { 88 lfa->lfa_flock.l_type = F_WRLCK; 89 } else if (strcmp(type, "unlock") == 0) { 90 lfa->lfa_flock.l_type = F_UNLCK; 91 } else { 92 free(lfa); 93 return (v8plus_error(V8PLUSERR_BADARG, "bad args: type")); 94 } 95 lfa->lfa_flock.l_whence = SEEK_SET; 96 lfa->lfa_flock.l_start = 0; 97 lfa->lfa_flock.l_len = 0; 98 99 100 if (lfa->lfa_run_sync) { 101 /* 102 * Run the blocking fcntl() call in the current thread: 103 */ 104 lockfd_thread(lfa); 105 } else { 106 /* 107 * Hold this function so that we can call it later from 108 * the other thread: 109 */ 110 v8plus_jsfunc_hold(lfa->lfa_cb); 111 112 /* 113 * Create a thread for the blocking fcntl(F_SETLKW) call: 114 */ 115 if (pthread_create(&newthr, NULL, lockfd_thread, lfa) != 0) { 116 return (v8plus_error(V8PLUSERR_UNKNOWN, 117 "could not create thread")); 118 } 119 } 120 121 return (v8plus_void()); 122 } 123 124 /* 125 * v8plus Boilerplate 126 */ 127 const v8plus_c_ctor_f v8plus_ctor = NULL; 128 const v8plus_c_dtor_f v8plus_dtor = NULL; 129 const char *v8plus_js_factory_name = NULL; 130 const char *v8plus_js_class_name = NULL; 131 132 const v8plus_method_descr_t v8plus_methods[] = {}; 133 const uint_t v8plus_method_count = 134 sizeof (v8plus_methods) / sizeof (v8plus_methods[0]); 135 136 const v8plus_static_descr_t v8plus_static_methods[] = { 137 { 138 sd_name: "lock_fd", 139 sd_c_func: lockfd_lockfd 140 } 141 }; 142 const uint_t v8plus_static_method_count = 143 sizeof (v8plus_static_methods) / sizeof (v8plus_static_methods[0]);