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