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