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]);