1 /* callback.c: Registering ML values for access from C code */
2
3 /* sestoft@dina.kvl.dk 1999-08-09 */
4
5 #include "callback.h"
6 #include "mlvalues.h" /* for Field, Reference_tag etc */
7 #include "fail.h" /* for failwith */
8 #include "memory.h" /* for alloc_shr */
9 #include "alloc.h" /* for copy_string */
10 #include "minor_gc.h" /* for minor_collection */
11 #include "interp.h" /* for callback */
12
13
14 /* ML closures for the functions to look up, register and unregister values */
15
16 static value get_valueptr_ = (value)NULL;
17 static valueptr reg_mlvalueptr_ptr_ = (valueptr)NULL;
18 static valueptr unreg_mlvalueptr_ptr_ = (valueptr)NULL;
19 static valueptr reg_cptr_ptr_ = (valueptr)NULL;
20
21 /* Obtain an ML value pointer from a string. Return NULL if the name
22 is not registered, or has been unregistered. */
23
get_valueptr(char * nam)24 valueptr get_valueptr(char* nam) {
25 /* opt is an ML option type */
26 value opt = callback(get_valueptr_, copy_string(nam));
27 if (opt == NONE) {
28 return (valueptr)NULL; /* Not an ML value */
29 } else
30 return (valueptr)(Field(opt, 0)); /* res = SOME valueptr */
31 }
32
33 /* Obtain an ML value from a value pointer. Fail if the value pointer
34 is NULL. Return NULL if the value has been unregistered. */
35
get_value(valueptr mvp)36 value get_value(valueptr mvp) {
37 value opt;
38 if (mvp == (valueptr)NULL)
39 failwith("get_value: null ML value pointer");
40 opt = Field(mvp, 0);
41 if (opt == NONE)
42 return (value)NULL; /* Not an ML value */
43 else
44 return (value)(Field(opt, 0)); /* opt == SOME v */
45 }
46
callbackptr(valueptr closureptr,value arg1)47 value callbackptr(valueptr closureptr, value arg1) {
48 value closure = get_value(closureptr);
49 if (closure == (value)NULL)
50 failwith("callbackptr: ML value has been unregistered");
51 return callback(closure, arg1);
52 }
53
callbackptr2(valueptr closureptr,value arg1,value arg2)54 value callbackptr2(valueptr closureptr, value arg1, value arg2) {
55 value closure = get_value(closureptr);
56 if (closure == (value)NULL)
57 failwith("callbackptr2: ML value has been unregistered");
58 return callback2(closure, arg1, arg2);
59 }
60
callbackptr3(valueptr closureptr,value arg1,value arg2,value arg3)61 value callbackptr3(valueptr closureptr, value arg1, value arg2, value arg3) {
62 value closure = get_value(closureptr);
63 if (closure == (value)NULL)
64 failwith("callbackptr3: ML value has been unregistered");
65 return callback3(closure, arg1, arg2, arg3);
66 }
67
68 /* This calls Callback.register */
69
registervalue(char * nam,value mlval)70 void registervalue(char* nam, value mlval) {
71 value namval;
72 Push_roots(r, 1);
73 r[0] = mlval;
74 namval = copy_string(nam);
75 callback2(get_value(reg_mlvalueptr_ptr_), namval, r[0]);
76 Pop_roots();
77 }
78
79 /* This calls Callback.unregister */
80
unregistervalue(char * nam)81 void unregistervalue(char* nam) {
82 value namval = copy_string(nam);
83 callback(get_value(unreg_mlvalueptr_ptr_), namval);
84 }
85
86 /* Allocate a reference cell in the old heap, so it will not be moved.
87 This is to be called from the ML side only: */
88
alloc_valueptr(value v)89 valueptr alloc_valueptr(value v) /* ML */
90 {
91 value res;
92 Push_roots(r, 1);
93 r[0] = v;
94 res = alloc_shr (1, Reference_tag); // An 'a ref
95 initialize(&Field(res, 0), r[0]);
96 Pop_roots();
97 return res;
98 }
99
registercptr(char * nam,void * cptr)100 void registercptr(char* nam, void* cptr) {
101 // A simple way to initialize the ML value pointer once
102 if (reg_cptr_ptr_ == (valueptr)NULL)
103 reg_cptr_ptr_ = get_valueptr("Callback.registercptr");
104 callbackptr2(reg_cptr_ptr_, copy_string(nam), (value)cptr);
105 }
106
107 /* Initialization. This is to be called from the ML side when the
108 Callback structure has been loaded, only then, and only once. It
109 saves the ML closure representing the registry lookup function, and
110 then obtains pointers to the ML closures for the Callback.register
111 and Callback.unregister functions. */
112
sml_init_register(value v)113 value sml_init_register(value v) /* ML */
114 {
115 /* The closure in v may be moved if it is not in the old heap. We
116 force it into the old heap by requesting a minor collection: */
117 Push_roots(r, 1);
118 r[0] = v;
119 minor_collection();
120 get_valueptr_ = r[0];
121 Pop_roots();
122 reg_mlvalueptr_ptr_ = get_valueptr("Callback.register");
123 unreg_mlvalueptr_ptr_ = get_valueptr("Callback.unregister");
124 return Val_unit;
125 }
126
127 /* Accessing C variables and functions from ML. Used by Dynlib and Callback */
128
c_var(value symhdl)129 value c_var(value symhdl) /* ML */
130 {
131 return *((value *) symhdl);
132 }
133
cfun_app1(value cfun,value arg)134 value cfun_app1(value cfun, value arg) /* ML */
135 {
136 /* Due to the heavy typecasting, I had to declare a temp variable in
137 order to get it right.
138 */
139 value (*cp)(value) = (value (*)(value)) cfun;
140
141 return (*cp)(arg);
142 }
143
cfun_app2(value cfun,value arg1,value arg2)144 value cfun_app2(value cfun, value arg1, value arg2) /* ML */
145 {
146 /* again a typecast value */
147 value (*cp)(value,value) = (value (*)(value,value)) cfun;
148
149 return (*cp)(arg1,arg2);
150 }
151
cfun_app3(value cfun,value arg1,value arg2,value arg3)152 value cfun_app3(value cfun, value arg1, value arg2, value arg3) /* ML */
153 {
154 /* again a typecast value */
155 value (*cp)(value,value,value) = (value (*)(value,value,value)) cfun;
156
157 return (*cp)(arg1,arg2,arg3);
158 }
159
cfun_app4(value cfun,value arg1,value arg2,value arg3,value arg4)160 value cfun_app4(value cfun, value arg1, value arg2, value arg3, value arg4) /* ML */
161 {
162 /* again a typecast value */
163 value (*cp)(value,value,value,value) =
164 (value (*)(value,value,value,value)) cfun;
165
166 return (*cp)(arg1,arg2,arg3,arg4);
167 }
168
cfun_app5(value args,int argc)169 value cfun_app5(value args, int argc) /* ML */
170 {
171 value cfun = Field(args, 0);
172 value arg1 = Field(args, 1);
173 value arg2 = Field(args, 2);
174 value arg3 = Field(args, 3);
175 value arg4 = Field(args, 4);
176 value arg5 = Field(args, 5);
177
178 /* again a typecast value */
179 value (*cp)(value,value,value,value,value) =
180 (value (*)(value,value,value,value,value)) cfun;
181
182 return (*cp)(arg1,arg2,arg3,arg4,arg5);
183 }
184