1 /********************************************
2 ** Do not edit this file!
3 ** This file is generated from foreign.rktc,
4 ** to make changes, edit that file and
5 ** run it to generate an updated version
6 ** of this file.
7 ********************************************/
8
9 #include "schpriv.h"
10 #include "schmach.h"
11 #include "schrktio.h"
12
13 #ifndef DONT_USE_FOREIGN
14
15 #include <errno.h>
16
17 #ifdef MZ_USE_FFIPOLL
18 # define MZ_USE_FFIPOLL_COND 1
19 #else /* MZ_USE_FFIPOLL undefined */
20 # define MZ_USE_FFIPOLL_COND 0
21 #endif /* MZ_USE_FFIPOLL */
22
23 #ifndef SIZEOF_BOOL
24 # define SIZEOF_BOOL 0
25 #endif /* SIZEOF_BOOL */
26 #if SIZEOF_BOOL != 0
27 # include <stdbool.h>
28 #endif /* SIZEOF_BOOL != 0 */
29
30 #ifndef WINDOWS_DYNAMIC_LOAD
31 # include <dlfcn.h>
32 #else /* WINDOWS_DYNAMIC_LOAD defined */
33 # include <windows.h>
34 #endif /* WINDOWS_DYNAMIC_LOAD */
35
36 #if !defined(WINDOWS_DYNAMIC_LOAD) || defined(__MINGW32__)
37 typedef signed char Tsint8;
38 typedef unsigned char Tuint8;
39
40 # if SIZEOF_SHORT == 2
41 typedef signed short Tsint16;
42 typedef unsigned short Tuint16;
43 # elif SIZEOF_INT == 2
44 typedef signed int Tsint16;
45 typedef unsigned int Tuint16;
46 # else
47 # error "configuration error, please contact PLT (int16)"
48 # endif
49
50 # if SIZEOF_INT == 4
51 typedef signed int Tsint32;
52 typedef unsigned int Tuint32;
53 # elif SIZEOF_LONG == 4
54 typedef signed long Tsint32;
55 typedef unsigned long Tuint32;
56 # else
57 # error "configuration error, please contact PLT (int32)"
58 # endif
59
60 # if SIZEOF_LONG == 8
61 typedef signed long Tsint64;
62 typedef unsigned long Tuint64;
63 # elif SIZEOF_LONG_LONG == 8
64 typedef signed long long Tsint64;
65 typedef unsigned long long Tuint64;
66 # else
67 # error "configuration error, please contact PLT (int64)"
68 # endif
69
70 #else /* !defined(WINDOWS_DYNAMIC_LOAD) || defined(__MINGW32__) */
71
72 # ifndef __CYGWIN32__
73 # include <wtypes.h>
74 typedef _int8 Tsint8;
75 typedef unsigned _int8 Tuint8;
76 typedef _int16 Tsint16;
77 typedef unsigned _int16 Tuint16;
78 typedef _int32 Tsint32;
79 typedef unsigned _int32 Tuint32;
80 typedef _int64 Tsint64;
81 typedef unsigned _int64 Tuint64;
82 # endif
83
84 #endif /* !defined(WINDOWS_DYNAMIC_LOAD) || defined(__MINGW32__) */
85
86 #include "ffi.h"
87
88 typedef void *(*Scheme_Malloc_Proc)(size_t);
89 static Scheme_Malloc_Proc mode_to_allocator(const char *who, Scheme_Object *mode);
90
91 static Scheme_Object *nonatomic_sym;
92 static Scheme_Object *atomic_sym;
93 static Scheme_Object *stubborn_sym;
94 static Scheme_Object *uncollectable_sym;
95 static Scheme_Object *eternal_sym;
96 static Scheme_Object *interior_sym;
97 static Scheme_Object *atomic_interior_sym;
98 static Scheme_Object *raw_sym;
99 static Scheme_Object *tagged_sym;
100 static Scheme_Object *fail_ok_sym;
101
102 #ifndef MZ_PRECISE_GC
103 # define XFORM_OK_PLUS +
104 # define GC_CAN_IGNORE /* empty */
105 #endif
106
107 #define W_OFFSET(src, delta) ((char *)(src) XFORM_OK_PLUS (delta))
108
109 /* same as the macro in file.c */
110 #define TO_PATH(x) (SCHEME_PATHP(x) ? (x) : scheme_char_string_to_path(x))
111
112 static void save_errno_values(int kind);
113
114 /* This make hides pointerness from cdefstruct so that it
115 doesn't generate a mark/fixup action: */
116 #define NON_GCBALE_PTR(t) t*
117
overflow_error(const char * who,const char * op,intptr_t a,intptr_t b)118 static void overflow_error(const char *who, const char *op, intptr_t a, intptr_t b)
119 {
120 scheme_contract_error(who, "arithmetic overflow",
121 "operation", 0, op,
122 "first argument", 1, scheme_make_integer(a),
123 "first argument", 1, scheme_make_integer(b),
124 NULL);
125 }
126
mult_check_overflow(const char * who,intptr_t a,intptr_t b)127 static intptr_t mult_check_overflow(const char *who, intptr_t a, intptr_t b)
128 {
129 Scheme_Object *c;
130 c = scheme_bin_mult(scheme_make_integer(a), scheme_make_integer(b));
131 if (!SCHEME_INTP(c))
132 overflow_error(who, "multiply", a, b);
133 return SCHEME_INT_VAL(c);
134 }
135
add_check_overflow(const char * who,intptr_t a,intptr_t b)136 static intptr_t add_check_overflow(const char *who, intptr_t a, intptr_t b)
137 {
138 Scheme_Object *c;
139 c = scheme_bin_plus(scheme_make_integer(a), scheme_make_integer(b));
140 if (!SCHEME_INTP(c))
141 overflow_error(who, "add", a, b);
142 return SCHEME_INT_VAL(c);
143 }
144
145 /*****************************************************************************/
146 /* Library objects */
147
148 /* ffi-lib structure definition */
149 static Scheme_Type ffi_lib_tag;
150 typedef struct ffi_lib_struct {
151 Scheme_Object so;
152 NON_GCBALE_PTR(rktio_dll_t) handle;
153 Scheme_Object* name;
154 int is_global;
155 int refcount;
156 } ffi_lib_struct;
157 #define SCHEME_FFILIBP(x) (SCHEME_TYPE(x)==ffi_lib_tag)
158 #define MYNAME "ffi-lib?"
foreign_ffi_lib_p(int argc,Scheme_Object * argv[])159 static Scheme_Object *foreign_ffi_lib_p(int argc, Scheme_Object *argv[])
160 {
161 return SCHEME_FFILIBP(argv[0]) ? scheme_true : scheme_false;
162 }
163 #undef MYNAME
164 /* 3m stuff for ffi_lib */
165 #ifdef MZ_PRECISE_GC
166 START_XFORM_SKIP;
ffi_lib_SIZE(void * p)167 int ffi_lib_SIZE(void *p) {
168 return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
169 }
ffi_lib_MARK(void * p)170 int ffi_lib_MARK(void *p) {
171 ffi_lib_struct *s = (ffi_lib_struct *)p;
172 gcMARK(s->name);
173 return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
174 }
ffi_lib_FIXUP(void * p)175 int ffi_lib_FIXUP(void *p) {
176 ffi_lib_struct *s = (ffi_lib_struct *)p;
177 gcFIXUP(s->name);
178 return gcBYTES_TO_WORDS(sizeof(ffi_lib_struct));
179 }
180 END_XFORM_SKIP;
181 #endif
182
183 THREAD_LOCAL_DECL(static Scheme_Hash_Table *opened_libs);
184
185 /* (ffi-lib filename no-error? global?) -> ffi-lib */
186 #define MYNAME "ffi-lib"
foreign_ffi_lib(int argc,Scheme_Object * argv[])187 static Scheme_Object *foreign_ffi_lib(int argc, Scheme_Object *argv[])
188 {
189 char *name;
190 Scheme_Object *path, *hashname;
191 rktio_dll_t *handle;
192 int as_global = 0;
193 ffi_lib_struct *lib;
194 if (!(SCHEME_PATH_STRINGP(argv[0]) || SCHEME_FALSEP(argv[0])))
195 scheme_wrong_contract(MYNAME, "(or/c string? #f)", 0, argc, argv);
196 as_global = ((argc > 2) && SCHEME_TRUEP(argv[2]));
197 /* leave the filename as given, the system will look for it */
198 /* (`#f' means open the executable) */
199 path = SCHEME_FALSEP(argv[0]) ? NULL : TO_PATH(argv[0]);
200 name = (path==NULL) ? NULL : SCHEME_PATH_VAL(path);
201 hashname = (Scheme_Object*)((name==NULL) ? "" : name);
202 lib = (ffi_lib_struct*)scheme_hash_get(opened_libs, hashname);
203 if (!lib) {
204 handle = rktio_dll_open(scheme_rktio, name, as_global);
205 if (!handle) {
206 char *msg;
207 msg = rktio_dll_get_error(scheme_rktio);
208 if (argc > 1 && SCHEME_TRUEP(argv[1])) {
209 if (msg) free(msg);
210 return scheme_false;
211 } else {
212 if (msg) {
213 msg = scheme_strdup_and_free(msg);
214 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
215 MYNAME": couldn't open %V (%s)", argv[0], msg);
216 } else
217 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
218 MYNAME": couldn't open %V (%R)", argv[0]);
219 }
220 }
221 lib = (ffi_lib_struct*)scheme_malloc_tagged(sizeof(ffi_lib_struct));
222 lib->so.type = ffi_lib_tag;
223 lib->handle = (handle);
224 lib->name = (argv[0]);
225 lib->is_global = (!name);
226 lib->refcount = (1);
227 scheme_hash_set(opened_libs, hashname, (Scheme_Object*)lib);
228 /* no dlclose finalizer - since the hash table always keeps a reference */
229 /* maybe add some explicit unload at some point */
230 } else
231 lib->refcount++;
232 return (Scheme_Object*)lib;
233 }
234 #undef MYNAME
235
236 /* (ffi-lib-name ffi-lib) -> string */
237 #define MYNAME "ffi-lib-name"
foreign_ffi_lib_name(int argc,Scheme_Object * argv[])238 static Scheme_Object *foreign_ffi_lib_name(int argc, Scheme_Object *argv[])
239 {
240 if (!SCHEME_FFILIBP(argv[0]))
241 scheme_wrong_contract(MYNAME, "ffi-lib?", 0, argc, argv);
242 return ((ffi_lib_struct*)argv[0])->name;
243 }
244 #undef MYNAME
245
246 /* (ffi-lib-unload ffi-lib) -> (void) */
247 #define MYNAME "ffi-lib-unload"
foreign_ffi_lib_unload(int argc,Scheme_Object * argv[])248 static Scheme_Object *foreign_ffi_lib_unload(int argc, Scheme_Object *argv[])
249 {
250 ffi_lib_struct *lib;
251
252 if (!SCHEME_FFILIBP(argv[0]))
253 scheme_wrong_contract(MYNAME, "ffi-lib?", 0, argc, argv);
254
255 lib = (ffi_lib_struct *)argv[0];
256 if (!lib->handle)
257 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
258 MYNAME": couldn't close already-closed lib %V",
259 lib->name);
260
261 --lib->refcount;
262 if (lib->refcount)
263 return scheme_void;
264
265 if (rktio_dll_close(scheme_rktio, lib->handle)) {
266 Scheme_Object *hashname;
267
268 lib->handle = NULL;
269
270 if (SCHEME_FALSEP(lib->name))
271 hashname = (Scheme_Object *)"";
272 else {
273 hashname = TO_PATH(lib->name);
274 hashname = (Scheme_Object *)SCHEME_PATH_VAL(hashname);
275 }
276 scheme_hash_set(opened_libs, hashname, NULL);
277 } else {
278 char *msg;
279 msg = rktio_dll_get_error(scheme_rktio);
280 if (msg) {
281 msg = scheme_strdup_and_free(msg);
282 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
283 MYNAME": couldn't close %V (%s)", lib->name, msg);
284 } else
285 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
286 MYNAME": couldn't close %V (%R)", lib->name);
287 }
288
289 return scheme_void;
290 }
291 #undef MYNAME
292
293 /*****************************************************************************/
294 /* Pull pointers (mostly functions) out of ffi-lib objects */
295
296 /* ffi-obj structure definition */
297 static Scheme_Type ffi_obj_tag;
298 typedef struct ffi_obj_struct {
299 Scheme_Object so;
300 NON_GCBALE_PTR(void) obj;
301 char* name;
302 NON_GCBALE_PTR(ffi_lib_struct) lib;
303 } ffi_obj_struct;
304 #define SCHEME_FFIOBJP(x) (SCHEME_TYPE(x)==ffi_obj_tag)
305 #define MYNAME "ffi-obj?"
foreign_ffi_obj_p(int argc,Scheme_Object * argv[])306 static Scheme_Object *foreign_ffi_obj_p(int argc, Scheme_Object *argv[])
307 {
308 return SCHEME_FFIOBJP(argv[0]) ? scheme_true : scheme_false;
309 }
310 #undef MYNAME
311 /* 3m stuff for ffi_obj */
312 #ifdef MZ_PRECISE_GC
313 START_XFORM_SKIP;
ffi_obj_SIZE(void * p)314 int ffi_obj_SIZE(void *p) {
315 return gcBYTES_TO_WORDS(sizeof(ffi_obj_struct));
316 }
ffi_obj_MARK(void * p)317 int ffi_obj_MARK(void *p) {
318 ffi_obj_struct *s = (ffi_obj_struct *)p;
319 gcMARK(s->name);
320 return gcBYTES_TO_WORDS(sizeof(ffi_obj_struct));
321 }
ffi_obj_FIXUP(void * p)322 int ffi_obj_FIXUP(void *p) {
323 ffi_obj_struct *s = (ffi_obj_struct *)p;
324 gcFIXUP(s->name);
325 return gcBYTES_TO_WORDS(sizeof(ffi_obj_struct));
326 }
327 END_XFORM_SKIP;
328 #endif
329
330 /* (ffi-obj objname ffi-lib-or-libname) -> ffi-obj */
331 #define MYNAME "ffi-obj"
foreign_ffi_obj(int argc,Scheme_Object * argv[])332 static Scheme_Object *foreign_ffi_obj(int argc, Scheme_Object *argv[])
333 {
334 ffi_obj_struct *obj;
335 void *dlobj;
336 ffi_lib_struct *lib = NULL;
337 char *dlname;
338 if (SCHEME_FFILIBP(argv[1]))
339 lib = (ffi_lib_struct*)argv[1];
340 else if (SCHEME_PATH_STRINGP(argv[1]) || SCHEME_FALSEP(argv[1]))
341 lib = (ffi_lib_struct*)(foreign_ffi_lib(1,&argv[1]));
342 else
343 scheme_wrong_contract(MYNAME, "ffi-lib?", 1, argc, argv);
344 if (!SCHEME_BYTE_STRINGP(argv[0]))
345 scheme_wrong_contract(MYNAME, "bytes?", 0, argc, argv);
346 dlname = SCHEME_BYTE_STR_VAL(argv[0]);
347
348 if (!lib->handle) {
349 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
350 MYNAME": couldn't get \"%s\" from already-closed %V",
351 dlname, lib->name);
352 }
353
354 dlobj = rktio_dll_find_object(scheme_rktio, lib->handle, dlname);
355 if (!dlobj) {
356 char *msg;
357 msg = rktio_dll_get_error(scheme_rktio);
358 if (msg) {
359 msg = scheme_strdup_and_free(msg);
360 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
361 MYNAME": couldn't get \"%s\" from %V (%s)",
362 dlname, lib->name, msg);
363 } else
364 scheme_raise_exn(MZEXN_FAIL_FILESYSTEM,
365 MYNAME": couldn't get \"%s\" from %V (%R)",
366 dlname, lib->name);
367 }
368
369 if (dlobj) {
370 obj = (ffi_obj_struct*)scheme_malloc_tagged(sizeof(ffi_obj_struct));
371 obj->so.type = ffi_obj_tag;
372 obj->obj = (dlobj);
373 obj->name = (dlname);
374 obj->lib = (lib);
375 return (Scheme_Object *)obj;
376 } else
377 return scheme_false;
378 }
379 #undef MYNAME
380
381 /* (ffi-obj-lib ffi-obj) -> ffi-lib */
382 #define MYNAME "ffi-obj-lib"
foreign_ffi_obj_lib(int argc,Scheme_Object * argv[])383 static Scheme_Object *foreign_ffi_obj_lib(int argc, Scheme_Object *argv[])
384 {
385 if (!SCHEME_FFIOBJP(argv[0]))
386 scheme_wrong_contract(MYNAME, "ffi-obj?", 0, argc, argv);
387 return (Scheme_Object*)(((ffi_obj_struct*)argv[0])->lib);
388 }
389 #undef MYNAME
390
391 /* (ffi-obj-name ffi-obj) -> string */
392 #define MYNAME "ffi-obj-name"
foreign_ffi_obj_name(int argc,Scheme_Object * argv[])393 static Scheme_Object *foreign_ffi_obj_name(int argc, Scheme_Object *argv[])
394 {
395 if (!SCHEME_FFIOBJP(argv[0]))
396 scheme_wrong_contract(MYNAME, "ffi-obj?", 0, argc, argv);
397 return scheme_make_byte_string(((ffi_obj_struct*)argv[0])->name);
398 }
399 #undef MYNAME
400
401 /*****************************************************************************/
402 /* Type helpers */
403
404 /* These are not defined in Racket because:
405 * - SCHEME_UINT_VAL is not really a simple accessor like other SCHEME_X_VALs
406 * - scheme_make_integer_from_unsigned behaves the same as the signed version
407 */
408 #define SCHEME_UINT_VAL(obj) ((unsigned)(SCHEME_INT_VAL(obj)))
409 #define scheme_make_integer_from_unsigned(i) \
410 ((Scheme_Object *)((((uintptr_t)i) << 1) | 0x1))
411
412 #ifndef SIXTY_FOUR_BIT_INTEGERS
413
414 /* longs and ints are really the same */
415 #define scheme_get_realint_val(x,y) \
416 scheme_get_int_val(x,(intptr_t*)(y))
417 #define scheme_get_unsigned_realint_val(x,y) \
418 scheme_get_unsigned_int_val(x,(uintptr_t*)(y))
419 #define scheme_make_realinteger_value \
420 scheme_make_integer_value
421 #define scheme_make_realinteger_value_from_unsigned \
422 scheme_make_integer_value_from_unsigned
423
424 #else /* SIXTY_FOUR_BIT_INTEGERS defined */
425
426 /* These will make sense in Racket when longs are longer than ints (needed
427 * for libffi's int32 types). There is no need to deal with bignums because
428 * racket's fixnums are longs. */
scheme_get_realint_val(Scheme_Object * o,int * v)429 XFORM_NONGCING int scheme_get_realint_val(Scheme_Object *o, int *v)
430 {
431 if (SCHEME_INTP(o)) {
432 uintptr_t lv = SCHEME_INT_VAL(o);
433 int i = (int)lv;
434 if (i != lv)
435 return 0;
436 *v = i;
437 return 1;
438 } else return 0;
439 }
scheme_get_unsigned_realint_val(Scheme_Object * o,unsigned int * v)440 XFORM_NONGCING int scheme_get_unsigned_realint_val(Scheme_Object *o, unsigned int *v)
441 {
442 if (SCHEME_INTP(o)) {
443 uintptr_t lv = SCHEME_INT_VAL(o);
444 unsigned int i = (unsigned int)lv;
445 if (i != lv)
446 return 0;
447 *v = i;
448 return 1;
449 } else return 0;
450 }
451 #define scheme_make_realinteger_value(ri) \
452 scheme_make_integer((intptr_t)(ri))
453 #define scheme_make_realinteger_value_from_unsigned(ri) \
454 scheme_make_integer((uintptr_t)(ri))
455
456 #endif /* SIXTY_FOUR_BIT_INTEGERS */
457
get_byte_val(Scheme_Object * o,Tsint8 * _v)458 XFORM_NONGCING MZ_INLINE static int get_byte_val(Scheme_Object *o, Tsint8 *_v)
459 {
460 if (SCHEME_INTP(o)) {
461 intptr_t v = SCHEME_INT_VAL(o);
462 if ((v >= -128) && (v <= 127)) {
463 *_v = v;
464 return 1;
465 }
466 }
467 return 0;
468 }
469
get_ubyte_val(Scheme_Object * o,Tuint8 * _v)470 XFORM_NONGCING MZ_INLINE static int get_ubyte_val(Scheme_Object *o, Tuint8 *_v)
471 {
472 if (SCHEME_INTP(o)) {
473 intptr_t v = SCHEME_INT_VAL(o);
474 if ((v >= 0) && (v <= 255)) {
475 *_v = v;
476 return 1;
477 }
478 }
479 return 0;
480 }
481
get_short_val(Scheme_Object * o,Tsint16 * _v)482 XFORM_NONGCING MZ_INLINE static int get_short_val(Scheme_Object *o, Tsint16 *_v)
483 {
484 if (SCHEME_INTP(o)) {
485 intptr_t v = SCHEME_INT_VAL(o);
486 if ((v >= -32768) && (v <= 32767)) {
487 *_v = v;
488 return 1;
489 }
490 }
491 return 0;
492 }
493
get_ushort_val(Scheme_Object * o,Tuint16 * _v)494 XFORM_NONGCING MZ_INLINE static int get_ushort_val(Scheme_Object *o, Tuint16 *_v)
495 {
496 if (SCHEME_INTP(o)) {
497 intptr_t v = SCHEME_INT_VAL(o);
498 if ((v >= 0) && (v <= 65536)) {
499 *_v = v;
500 return 1;
501 }
502 }
503 return 0;
504 }
505
506 /* This is related to the section of scheme.h that defines mzlonglong. */
507 #ifndef INT64_AS_LONG_LONG
508 #ifdef NO_LONG_LONG_TYPE
509 #ifndef SIXTY_FOUR_BIT_INTEGERS
510 #error foreign requires a 64-bit integer type type.
511 #endif
512 #endif
513 #endif
514
515 #define SCHEME_FALSEP_OR_CHAR_STRINGP(o) (SCHEME_FALSEP(o) || SCHEME_CHAR_STRINGP(o))
516
ucs4_string_or_null_to_ucs4_pointer(Scheme_Object * ucs)517 XFORM_NONGCING static mzchar *ucs4_string_or_null_to_ucs4_pointer(Scheme_Object *ucs)
518 {
519 if (SCHEME_FALSEP(ucs)) return NULL;
520 return SCHEME_CHAR_STR_VAL(ucs);
521 }
522
ucs4_string_to_utf16_pointer(Scheme_Object * ucs)523 static unsigned short *ucs4_string_to_utf16_pointer(Scheme_Object *ucs)
524 {
525 intptr_t ulen;
526 unsigned short *res;
527 res = scheme_ucs4_to_utf16
528 (SCHEME_CHAR_STR_VAL(ucs), 0, SCHEME_CHAR_STRLEN_VAL(ucs),
529 NULL, -1, &ulen, 1);
530 res[ulen] = 0;
531 return res;
532 }
533
ucs4_string_or_null_to_utf16_pointer(Scheme_Object * ucs)534 static unsigned short *ucs4_string_or_null_to_utf16_pointer(Scheme_Object *ucs)
535 {
536 if (SCHEME_FALSEP(ucs)) return NULL;
537 return ucs4_string_to_utf16_pointer(ucs);
538 }
539
utf16_pointer_to_ucs4_string(unsigned short * utf)540 static Scheme_Object *utf16_pointer_to_ucs4_string(unsigned short *utf)
541 {
542 intptr_t ulen, end;
543 mzchar *res;
544 if (!utf) return scheme_false;
545 for (end=0; utf[end] != 0; end++) { /**/ }
546 res = scheme_utf16_to_ucs4(utf, 0, end, NULL, -1, &ulen, 1);
547 res[ulen] = 0;
548 return scheme_make_sized_char_string(res, ulen, 0);
549 }
550
551 /*****************************************************************************/
552 /* Types */
553
554 #define MZ_TYPE_CAST(t, e) (t)(e)
555 #define MZ_NO_TYPE_CAST(t, e) (e)
556
557 /***********************************************************************
558 * The following are the only primitive types.
559 * The tricky part is figuring out what width-ed types correspond to
560 * what internal types. Matthew says:
561 * Racket expects to be compiled such that sizeof(int) == 4,
562 * sizeof(intptr_t) == sizeof(void*), sizeof(short) >= 2,
563 * sizeof(char) == 1, sizeof(float) == 4, and sizeof(double) == 8.
564 * So, on a 64-bit OS, Racket expects only `long' and `intptr_t' to change.
565 **********************************************************************/
566
567 /* returns #<void> when used as output type, not for input types. */
568 #define FOREIGN_void (1)
569 /* Type Name: void
570 * LibFfi type: ffi_type_void
571 * C type: -none-
572 * Predicate: -none-
573 * Racket->C: -none-
574 * S->C offset: 0
575 * C->Racket: scheme_void
576 */
577
578 #define FOREIGN_int8 (2)
579 /* Type Name: int8
580 * LibFfi type: ffi_type_sint8
581 * C type: Tsint8
582 * Predicate: get_byte_val(<Scheme>,&aux)
583 * Racket->C: -none- (set by the predicate)
584 * S->C offset: 0
585 * C->Racket: scheme_make_integer(<C>)
586 */
587
588 #define FOREIGN_uint8 (3)
589 /* Type Name: uint8
590 * LibFfi type: ffi_type_uint8
591 * C type: Tuint8
592 * Predicate: get_ubyte_val(<Scheme>,&aux)
593 * Racket->C: -none- (set by the predicate)
594 * S->C offset: 0
595 * C->Racket: scheme_make_integer(<C>)
596 */
597
598 #define FOREIGN_int16 (4)
599 /* Type Name: int16
600 * LibFfi type: ffi_type_sint16
601 * C type: Tsint16
602 * Predicate: get_short_val(<Scheme>,&aux)
603 * Racket->C: -none- (set by the predicate)
604 * S->C offset: 0
605 * C->Racket: scheme_make_integer(<C>)
606 */
607
608 #define FOREIGN_uint16 (5)
609 /* Type Name: uint16
610 * LibFfi type: ffi_type_uint16
611 * C type: Tuint16
612 * Predicate: get_ushort_val(<Scheme>,&aux)
613 * Racket->C: -none- (set by the predicate)
614 * S->C offset: 0
615 * C->Racket: scheme_make_integer(<C>)
616 */
617
618 /* Treats integers properly: */
619 #define FOREIGN_int32 (6)
620 /* Type Name: int32
621 * LibFfi type: ffi_type_sint32
622 * C type: Tsint32
623 * Predicate: scheme_get_realint_val(<Scheme>,&aux)
624 * Racket->C: -none- (set by the predicate)
625 * S->C offset: 0
626 * C->Racket: scheme_make_realinteger_value(<C>)
627 */
628
629 /* Treats integers properly: */
630 #define FOREIGN_uint32 (7)
631 /* Type Name: uint32
632 * LibFfi type: ffi_type_uint32
633 * C type: Tuint32
634 * Predicate: scheme_get_unsigned_realint_val(<Scheme>,&aux)
635 * Racket->C: -none- (set by the predicate)
636 * S->C offset: 0
637 * C->Racket: scheme_make_realinteger_value_from_unsigned(<C>)
638 */
639
640 #define FOREIGN_int64 (8)
641 /* Type Name: int64
642 * LibFfi type: ffi_type_sint64
643 * C type: Tsint64
644 * Predicate: scheme_get_long_long_val(<Scheme>,&aux)
645 * Racket->C: -none- (set by the predicate)
646 * S->C offset: 0
647 * C->Racket: scheme_make_integer_value_from_long_long(<C>)
648 */
649
650 #define FOREIGN_uint64 (9)
651 /* Type Name: uint64
652 * LibFfi type: ffi_type_uint64
653 * C type: Tuint64
654 * Predicate: scheme_get_unsigned_long_long_val(<Scheme>,&aux)
655 * Racket->C: -none- (set by the predicate)
656 * S->C offset: 0
657 * C->Racket: scheme_make_integer_value_from_unsigned_long_long(<C>)
658 */
659
660 /* This is like int32, but always assumes fixnum: */
661 #define FOREIGN_fixint (10)
662 /* Type Name: fixint
663 * LibFfi type: ffi_type_sint32
664 * C type: Tsint32
665 * Predicate: SCHEME_INTP(<Scheme>)
666 * Racket->C: SCHEME_INT_VAL(<Scheme>)
667 * S->C offset: 0
668 * C->Racket: scheme_make_integer(<C>)
669 */
670
671 /* This is like uint32, but always assumes fixnum: */
672 #define FOREIGN_ufixint (11)
673 /* Type Name: ufixint
674 * LibFfi type: ffi_type_uint32
675 * C type: Tuint32
676 * Predicate: SCHEME_INTP(<Scheme>)
677 * Racket->C: SCHEME_UINT_VAL(<Scheme>)
678 * S->C offset: 0
679 * C->Racket: scheme_make_integer_from_unsigned(<C>)
680 */
681
682 #ifndef SIXTY_FOUR_BIT_LONGS
683 #define ffi_type_smzlong ffi_type_sint32
684 #define ffi_type_umzlong ffi_type_uint32
685 #else /* SIXTY_FOUR_BIT_LONGS defined */
686 #define ffi_type_smzlong ffi_type_sint64
687 #define ffi_type_umzlong ffi_type_uint64
688 #endif /* SIXTY_FOUR_BIT_LONGS */
689
690 #ifndef SIXTY_FOUR_BIT_INTEGERS
691 #define ffi_type_smzintptr ffi_type_sint32
692 #define ffi_type_umzintptr ffi_type_uint32
693 #else /* SIXTY_FOUR_BIT_INTEGERS defined */
694 #define ffi_type_smzintptr ffi_type_sint64
695 #define ffi_type_umzintptr ffi_type_uint64
696 #endif /* SIXTY_FOUR_BIT_INTEGERS */
697
698 /* This is what mzscheme defines as intptr, assuming fixnums: */
699 #define FOREIGN_fixnum (12)
700 /* Type Name: fixnum
701 * LibFfi type: ffi_type_smzintptr
702 * C type: intptr_t
703 * Predicate: SCHEME_INTP(<Scheme>)
704 * Racket->C: SCHEME_INT_VAL(<Scheme>)
705 * S->C offset: 0
706 * C->Racket: scheme_make_integer(<C>)
707 */
708
709 /* This is what mzscheme defines as uintptr, assuming fixnums: */
710 #define FOREIGN_ufixnum (13)
711 /* Type Name: ufixnum
712 * LibFfi type: ffi_type_umzintptr
713 * C type: uintptr_t
714 * Predicate: SCHEME_INTP(<Scheme>)
715 * Racket->C: SCHEME_UINT_VAL(<Scheme>)
716 * S->C offset: 0
717 * C->Racket: scheme_make_integer_from_unsigned(<C>)
718 */
719
720 #define FOREIGN_float (14)
721 /* Type Name: float
722 * LibFfi type: ffi_type_float
723 * C type: float
724 * Predicate: SCHEME_FLOATP(<Scheme>)
725 * Racket->C: SCHEME_FLOAT_VAL(<Scheme>)
726 * S->C offset: 0
727 * C->Racket: scheme_make_double(<C>)
728 */
729
730 #define FOREIGN_double (15)
731 /* Type Name: double
732 * LibFfi type: ffi_type_double
733 * C type: double
734 * Predicate: SCHEME_FLOATP(<Scheme>)
735 * Racket->C: SCHEME_FLOAT_VAL(<Scheme>)
736 * S->C offset: 0
737 * C->Racket: scheme_make_double(<C>)
738 */
739
740 #ifdef _MSC_VER
741 struct struct_align_slongdouble {
742 char c;
743 long_double x;
744 };
745 const ffi_type ffi_type_slongdouble = {
746 sizeof(long_double),
747 offsetof(struct struct_align_slongdouble, x),
748 FFI_TYPE_STRUCT, NULL
749 };
750 #else /* _MSC_VER undefined */
751 #define ffi_type_slongdouble ffi_type_longdouble
752 #endif /* _MSC_VER */
753 #ifdef MZ_LONG_DOUBLE
754 #define SCHEME_MAYBE_LONG_DBL_VAL(x) SCHEME_LONG_DBL_VAL(x)
755 #else /* MZ_LONG_DOUBLE undefined */
756 #define SCHEME_MAYBE_LONG_DBL_VAL(x) unsupported_long_double_val()
unsupported_long_double_val()757 static mz_long_double unsupported_long_double_val() {
758 scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, "_longdouble: " NOT_SUPPORTED_STR);
759 return 0.0;
760 }
761 #endif /* MZ_LONG_DOUBLE */
762 #ifdef MZ_LONG_DOUBLE
763 #define scheme_make_maybe_long_double(x) scheme_make_long_double(x)
764 #else /* MZ_LONG_DOUBLE undefined */
765 #define scheme_make_maybe_long_double(x) unsupported_make_long_double()
unsupported_make_long_double()766 static Scheme_Object *unsupported_make_long_double() {
767 scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED, "_longdouble: " NOT_SUPPORTED_STR);
768 return NULL;
769 }
770 #endif /* MZ_LONG_DOUBLE */
771
772 #define FOREIGN_longdouble (16)
773 /* Type Name: longdouble
774 * LibFfi type: ffi_type_slongdouble
775 * C type: mz_long_double
776 * Predicate: SCHEME_LONG_DBLP(<Scheme>)
777 * Racket->C: SCHEME_MAYBE_LONG_DBL_VAL(<Scheme>)
778 * S->C offset: 0
779 * C->Racket: scheme_make_maybe_long_double(<C>)
780 */
781
782
783 /* A double that will coerce numbers to doubles: */
784 #define FOREIGN_doubleS (17)
785 /* Type Name: double* (doubleS)
786 * LibFfi type: ffi_type_double
787 * C type: double
788 * Predicate: SCHEME_REALP(<Scheme>)
789 * Racket->C: scheme_real_to_double(<Scheme>)
790 * S->C offset: 0
791 * C->Racket: scheme_make_double(<C>)
792 */
793
794 /* Booleans -- implemented as an int which is 1 or 0: */
795 #define FOREIGN_bool (18)
796 /* Type Name: bool
797 * LibFfi type: ffi_type_sint
798 * C type: int
799 * Predicate: 1
800 * Racket->C: SCHEME_TRUEP(<Scheme>)
801 * S->C offset: 0
802 * C->Racket: (<C>?scheme_true:scheme_false)
803 */
804
805 #if SIZEOF_BOOL == 0
806 typedef signed char stdbool;
807 # define ffi_type_stdbool ffi_type_sint8
808 #else /* SIZEOF_BOOL == 0 */
809 typedef bool stdbool;
810 #if SIZEOF_BOOL == 1
811 # define ffi_type_stdbool ffi_type_sint8
812 #else /* SIZEOF_BOOL == 1 */
813 #if SIZEOF_BOOL == 2
814 # define ffi_type_stdbool ffi_type_sint16
815 #else /* SIZEOF_BOOL == 2 */
816 #if SIZEOF_BOOL == 4
817 # define ffi_type_stdbool ffi_type_sint32
818 #else /* SIZEOF_BOOL == 4 */
819 #if SIZEOF_BOOL == 8
820 # define ffi_type_stdbool ffi_type_sint64
821 #else /* SIZEOF_BOOL == 8 */
822 /* ??? Pick something */
823 # define ffi_type_stdbool ffi_type_int
824 #endif /* SIZEOF_BOOL == 8 */
825 #endif /* SIZEOF_BOOL == 4 */
826 #endif /* SIZEOF_BOOL == 2 */
827 #endif /* SIZEOF_BOOL == 1 */
828 #endif /* SIZEOF_BOOL == 0 */
829
830 /* Booleans -- implemented as an int which is 1 or 0: */
831 #define FOREIGN_stdbool (19)
832 /* Type Name: stdbool
833 * LibFfi type: ffi_type_stdbool
834 * C type: stdbool
835 * Predicate: 1
836 * Racket->C: SCHEME_TRUEP(<Scheme>)
837 * S->C offset: 0
838 * C->Racket: (<C>?scheme_true:scheme_false)
839 */
840
841 /* Strings -- no copying is done (when possible).
842 * #f is not NULL only for byte-strings, for other strings it is
843 * meaningless to use NULL. */
844
845 #define FOREIGN_string_ucs_4 (20)
846 /* Type Name: string/ucs-4 (string_ucs_4)
847 * LibFfi type: ffi_type_gcpointer
848 * C type: mzchar*
849 * Predicate: SCHEME_FALSEP_OR_CHAR_STRINGP(<Scheme>)
850 * Racket->C: ucs4_string_or_null_to_ucs4_pointer(<Scheme>)
851 * S->C offset: 0
852 * C->Racket: scheme_make_char_string_without_copying(<C>)
853 */
854
855 #define FOREIGN_string_utf_16 (21)
856 /* Type Name: string/utf-16 (string_utf_16)
857 * LibFfi type: ffi_type_gcpointer
858 * C type: unsigned short*
859 * Predicate: SCHEME_FALSEP_OR_CHAR_STRINGP(<Scheme>)
860 * Racket->C: ucs4_string_or_null_to_utf16_pointer(<Scheme>)
861 * S->C offset: 0
862 * C->Racket: utf16_pointer_to_ucs4_string(<C>)
863 */
864
865 /* Byte strings -- not copying C strings, #f is NULL.
866 * (note: these are not like char* which is just a pointer) */
867
868 #define FOREIGN_bytes (22)
869 /* Type Name: bytes
870 * LibFfi type: ffi_type_gcpointer
871 * C type: char*
872 * Predicate: SCHEME_FALSEP(<Scheme>)||SCHEME_BYTE_STRINGP(<Scheme>)
873 * Racket->C: SCHEME_FALSEP(<Scheme>)?NULL:SCHEME_BYTE_STR_VAL(<Scheme>)
874 * S->C offset: 0
875 * C->Racket: (<C>==NULL)?scheme_false:scheme_make_byte_string_without_copying(<C>)
876 */
877
878 #define FOREIGN_path (23)
879 /* Type Name: path
880 * LibFfi type: ffi_type_gcpointer
881 * C type: char*
882 * Predicate: SCHEME_FALSEP(<Scheme>)||SCHEME_PATH_STRINGP(<Scheme>)
883 * Racket->C: SCHEME_FALSEP(<Scheme>)?NULL:SCHEME_PATH_VAL(TO_PATH(<Scheme>))
884 * S->C offset: 0
885 * C->Racket: (<C>==NULL)?scheme_false:scheme_make_path_without_copying(<C>)
886 */
887
888 #define FOREIGN_symbol (24)
889 /* Type Name: symbol
890 * LibFfi type: ffi_type_pointer
891 * C type: char*
892 * Predicate: SCHEME_SYMBOLP(<Scheme>)
893 * Racket->C: SCHEME_SYM_VAL(<Scheme>)
894 * S->C offset: 0
895 * C->Racket: scheme_intern_symbol(<C>)
896 */
897
898 /* This is for any C pointer: #f is NULL, cpointer values as well as
899 * ffi-obj and string values pass their pointer. When used as a return
900 * value, either a cpointer object or #f is returned. */
901 #define FOREIGN_pointer (25)
902 /* Type Name: pointer
903 * LibFfi type: ffi_type_pointer
904 * C type: void*
905 * Predicate: SCHEME_FFIANYPTRP(<Scheme>)
906 * Racket->C: SCHEME_FFIANYPTR_VAL(<Scheme>)
907 * S->C offset: FFIANYPTR
908 * C->Racket: scheme_make_foreign_external_cpointer(<C>)
909 */
910
911 #define FOREIGN_gcpointer (26)
912 /* Type Name: gcpointer
913 * LibFfi type: ffi_type_gcpointer
914 * C type: void*
915 * Predicate: SCHEME_FFIANYPTRP(<Scheme>)
916 * Racket->C: SCHEME_FFIANYPTR_VAL(<Scheme>)
917 * S->C offset: FFIANYPTR
918 * C->Racket: scheme_make_foreign_cpointer(<C>)
919 */
920
921 /* This is used for passing and Scheme_Object* value as is. Useful for
922 * functions that know about Scheme_Object*s, like Racket's. */
923 #define FOREIGN_scheme (27)
924 /* Type Name: scheme
925 * LibFfi type: ffi_type_gcpointer
926 * C type: Scheme_Object*
927 * Predicate: 1
928 * Racket->C: <Scheme>
929 * S->C offset: 0
930 * C->Racket: <C>
931 */
932
933 /* Special type, not actually used for anything except to mark values
934 * that are treated like pointers but not referenced. Used for
935 * creating function types. */
936 #define FOREIGN_fpointer (28)
937 /* Type Name: fpointer
938 * LibFfi type: ffi_type_pointer
939 * C type: void*
940 * Predicate: -none-
941 * Racket->C: -none-
942 * S->C offset: 0
943 * C->Racket: -none-
944 */
945
946 typedef union _ForeignAny {
947 Tsint8 x_int8;
948 Tuint8 x_uint8;
949 Tsint16 x_int16;
950 Tuint16 x_uint16;
951 Tsint32 x_int32;
952 Tuint32 x_uint32;
953 Tsint64 x_int64;
954 Tuint64 x_uint64;
955 Tsint32 x_fixint;
956 Tuint32 x_ufixint;
957 intptr_t x_fixnum;
958 uintptr_t x_ufixnum;
959 float x_float;
960 double x_double;
961 mz_long_double x_longdouble;
962 double x_doubleS;
963 int x_bool;
964 stdbool x_stdbool;
965 mzchar* x_string_ucs_4;
966 unsigned short* x_string_utf_16;
967 char* x_bytes;
968 char* x_path;
969 char* x_symbol;
970 void* x_pointer;
971 void* x_gcpointer;
972 Scheme_Object* x_scheme;
973 void* x_fpointer;
974 } ForeignAny;
975
976 /* This is a tag that is used to identify user-made struct types. */
977 #define FOREIGN_struct (29)
978 #define FOREIGN_array (30)
979 #define FOREIGN_union (31)
980
is_gcable_pointer(Scheme_Object * o)981 XFORM_NONGCING static int is_gcable_pointer(Scheme_Object *o) {
982 if (SCHEME_FFIOBJP(o)) return 0;
983 return (!SCHEME_CPTRP(o)
984 || !(SCHEME_CPTR_FLAGS(o) & 0x1));
985 }
986
987 /*****************************************************************************/
988 /* Type objects */
989
990 /* This struct is used for both user types and primitive types (including
991 * struct types). If it is a user type then basetype will be another ctype,
992 * otherwise,
993 * - if it's a primitive type, then basetype will be a symbol naming that type
994 * - if it's a struct or union, then basetype will be the list of ctypes that
995 * made this struct, prefixed with a symbol if the allocation mode is not 'atomic
996 * scheme_to_c will have the &ffi_type pointer, and c_to_scheme will have an
997 * integer (a label value) for non-struct type. (Note that the
998 * integer is not really needed, since it is possible to identify the
999 * type by the basetype field.)
1000 */
1001 /* ctype structure definition */
1002 #define ctype_tag scheme_ctype_type
1003 typedef struct ctype_struct {
1004 Scheme_Object so;
1005 Scheme_Object* basetype;
1006 Scheme_Object* scheme_to_c;
1007 Scheme_Object* c_to_scheme;
1008 } ctype_struct;
1009 #define SCHEME_CTYPEP(x) (SCHEME_TYPE(x)==ctype_tag)
1010 #define MYNAME "ctype?"
foreign_ctype_p(int argc,Scheme_Object * argv[])1011 static Scheme_Object *foreign_ctype_p(int argc, Scheme_Object *argv[])
1012 {
1013 return SCHEME_CTYPEP(argv[0]) ? scheme_true : scheme_false;
1014 }
1015 #undef MYNAME
1016 /* 3m stuff for ctype */
1017 #ifdef MZ_PRECISE_GC
1018 START_XFORM_SKIP;
ctype_SIZE(void * p)1019 int ctype_SIZE(void *p) {
1020 return gcBYTES_TO_WORDS(sizeof(ctype_struct));
1021 }
ctype_MARK(void * p)1022 int ctype_MARK(void *p) {
1023 ctype_struct *s = (ctype_struct *)p;
1024 gcMARK(s->basetype);
1025 gcMARK(s->scheme_to_c);
1026 gcMARK(s->c_to_scheme);
1027 return gcBYTES_TO_WORDS(sizeof(ctype_struct));
1028 }
ctype_FIXUP(void * p)1029 int ctype_FIXUP(void *p) {
1030 ctype_struct *s = (ctype_struct *)p;
1031 gcFIXUP(s->basetype);
1032 gcFIXUP(s->scheme_to_c);
1033 gcFIXUP(s->c_to_scheme);
1034 return gcBYTES_TO_WORDS(sizeof(ctype_struct));
1035 }
1036 END_XFORM_SKIP;
1037 #endif
1038
1039 static ffi_type ffi_type_gcpointer;
1040
1041 #define CTYPE_BASETYPE(x) (((ctype_struct*)(x))->basetype)
1042 #define CTYPE_USERP(x) (CTYPE_BASETYPE(x) != NULL && SCHEME_CTYPEP(CTYPE_BASETYPE(x)))
1043 #define CTYPE_PRIMP(x) (!CTYPE_USERP(x))
1044 #define CTYPE_PRIMTYPE(x) ((ffi_type*)(((ctype_struct*)(x))->scheme_to_c))
1045 #define CTYPE_PRIMLABEL(x) ((intptr_t)(((ctype_struct*)(x))->c_to_scheme))
1046 #define CTYPE_USER_S2C(x) (((ctype_struct*)(x))->scheme_to_c)
1047 #define CTYPE_USER_C2S(x) (((ctype_struct*)(x))->c_to_scheme)
1048
1049 #define CTYPE_ARG_PRIMTYPE(x) ((CTYPE_PRIMLABEL(x) == FOREIGN_array) ? &ffi_type_pointer : CTYPE_PRIMTYPE(x))
1050
1051 /* Returns #f for primitive types. */
1052 #define MYNAME "ctype-basetype"
foreign_ctype_basetype(int argc,Scheme_Object * argv[])1053 static Scheme_Object *foreign_ctype_basetype(int argc, Scheme_Object *argv[])
1054 {
1055 Scheme_Object *r;
1056 if (!SCHEME_CTYPEP(argv[0]))
1057 scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1058 r = CTYPE_BASETYPE(argv[0]);
1059 if (SCHEME_PAIRP(r) && SCHEME_SYMBOLP(SCHEME_CAR(r))) {
1060 /* strip allocation mode for struct/union */
1061 r = SCHEME_CDR(r);
1062 }
1063 return r;
1064 }
1065 #undef MYNAME
1066
1067 #define MYNAME "ctype-scheme->c"
foreign_ctype_scheme_to_c(int argc,Scheme_Object * argv[])1068 static Scheme_Object *foreign_ctype_scheme_to_c(int argc, Scheme_Object *argv[])
1069 {
1070 if (!SCHEME_CTYPEP(argv[0]))
1071 scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1072 return (CTYPE_PRIMP(argv[0])) ? scheme_false :
1073 ((ctype_struct*)(argv[0]))->scheme_to_c;
1074 }
1075 #undef MYNAME
1076
1077 #define MYNAME "ctype-c->scheme"
foreign_ctype_c_to_scheme(int argc,Scheme_Object * argv[])1078 static Scheme_Object *foreign_ctype_c_to_scheme(int argc, Scheme_Object *argv[])
1079 {
1080 if (!SCHEME_CTYPEP(argv[0]))
1081 scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1082 return (CTYPE_PRIMP(argv[0])) ? scheme_false :
1083 ((ctype_struct*)(argv[0]))->c_to_scheme;
1084 }
1085 #undef MYNAME
1086
1087 /* Returns a primitive type, or NULL if not a type */
get_ctype_base(Scheme_Object * type)1088 XFORM_NONGCING static Scheme_Object *get_ctype_base(Scheme_Object *type)
1089 {
1090 if (!SCHEME_CTYPEP(type)) return NULL;
1091 while (CTYPE_USERP(type)) { type = CTYPE_BASETYPE(type); }
1092 return type;
1093 }
1094
1095 /* Returns the size, 0 for void, -1 if no such type */
ctype_sizeof(Scheme_Object * type)1096 XFORM_NONGCING static intptr_t ctype_sizeof(Scheme_Object *type)
1097 {
1098 type = get_ctype_base(type);
1099 if (type == NULL) return -1;
1100 switch (CTYPE_PRIMLABEL(type)) {
1101 case FOREIGN_void: return 0;
1102 case FOREIGN_int8: return sizeof(Tsint8);
1103 case FOREIGN_uint8: return sizeof(Tuint8);
1104 case FOREIGN_int16: return sizeof(Tsint16);
1105 case FOREIGN_uint16: return sizeof(Tuint16);
1106 case FOREIGN_int32: return sizeof(Tsint32);
1107 case FOREIGN_uint32: return sizeof(Tuint32);
1108 case FOREIGN_int64: return sizeof(Tsint64);
1109 case FOREIGN_uint64: return sizeof(Tuint64);
1110 case FOREIGN_fixint: return sizeof(Tsint32);
1111 case FOREIGN_ufixint: return sizeof(Tuint32);
1112 case FOREIGN_fixnum: return sizeof(intptr_t);
1113 case FOREIGN_ufixnum: return sizeof(uintptr_t);
1114 case FOREIGN_float: return sizeof(float);
1115 case FOREIGN_double: return sizeof(double);
1116 case FOREIGN_longdouble: return sizeof(mz_long_double);
1117 case FOREIGN_doubleS: return sizeof(double);
1118 case FOREIGN_bool: return sizeof(int);
1119 case FOREIGN_stdbool: return sizeof(stdbool);
1120 case FOREIGN_string_ucs_4: return sizeof(mzchar*);
1121 case FOREIGN_string_utf_16: return sizeof(unsigned short*);
1122 case FOREIGN_bytes: return sizeof(char*);
1123 case FOREIGN_path: return sizeof(char*);
1124 case FOREIGN_symbol: return sizeof(char*);
1125 case FOREIGN_pointer: return sizeof(void*);
1126 case FOREIGN_gcpointer: return sizeof(void*);
1127 case FOREIGN_scheme: return sizeof(Scheme_Object*);
1128 case FOREIGN_fpointer: return sizeof(void*);
1129 /* for structs and arrays */
1130 default: return CTYPE_PRIMTYPE(type)->size;
1131 }
1132 }
1133
1134 /* (make-ctype basetype scheme->c c->scheme) -> ctype */
1135 /* The scheme->c can throw type errors to check for valid arguments */
1136 /* a #f means no conversion function, if both are #f -- then just return the */
1137 /* basetype. */
1138 #define MYNAME "make-ctype"
foreign_make_ctype(int argc,Scheme_Object * argv[])1139 static Scheme_Object *foreign_make_ctype(int argc, Scheme_Object *argv[])
1140 {
1141 ctype_struct *type;
1142 if (!SCHEME_CTYPEP(argv[0]))
1143 scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1144 else if (!(SCHEME_FALSEP(argv[1]) || SCHEME_PROCP(argv[1])))
1145 scheme_wrong_contract(MYNAME, "(or/c procedure? #f)", 1, argc, argv);
1146 else if (!(SCHEME_FALSEP(argv[2]) || SCHEME_PROCP(argv[2])))
1147 scheme_wrong_contract(MYNAME, "(or/c procedure? #f)", 2, argc, argv);
1148 else if (SCHEME_FALSEP(argv[1]) && SCHEME_FALSEP(argv[2]))
1149 return argv[0];
1150 else {
1151 type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1152 type->so.type = ctype_tag;
1153 type->basetype = (argv[0]);
1154 type->scheme_to_c = (argv[1]);
1155 type->c_to_scheme = (argv[2]);
1156 return (Scheme_Object*)type;
1157 }
1158 return NULL; /* hush the compiler */
1159 }
1160 #undef MYNAME
1161
1162 /* see below */
free_libffi_type(void * ignored,void * p)1163 static void free_libffi_type(void *ignored, void *p)
1164 {
1165 free(((ffi_type*)p)->elements);
1166 free(p);
1167 }
1168
free_libffi_type_two_layers(void * ignored,void * p)1169 static void free_libffi_type_two_layers(void *ignored, void *p)
1170 {
1171 int i;
1172
1173 for (i = 0; ((ffi_type*)p)->elements[i]; i++) {
1174 free(((ffi_type*)p)->elements[i]);
1175 }
1176 free_libffi_type(ignored, p);
1177 }
1178
1179 /*****************************************************************************/
1180 /* ABI spec */
1181
1182 static Scheme_Object *default_sym;
1183 static Scheme_Object *stdcall_sym;
1184 static Scheme_Object *sysv_sym;
1185
sym_to_abi(const char * who,Scheme_Object * sym)1186 static ffi_abi sym_to_abi(const char *who, Scheme_Object *sym)
1187 {
1188 if (SCHEME_FALSEP(sym) || SAME_OBJ(sym, default_sym))
1189 return FFI_DEFAULT_ABI;
1190 else if (SAME_OBJ(sym, sysv_sym)) {
1191 #if defined(WINDOWS_DYNAMIC_LOAD) && !defined(_WIN64)
1192 return FFI_SYSV;
1193 #else
1194 scheme_signal_error("%s: ABI not implemented: %V", who, sym);
1195 #endif
1196 } else if (SAME_OBJ(sym, stdcall_sym)) {
1197 #if defined(WINDOWS_DYNAMIC_LOAD) && !defined(_WIN64)
1198 return FFI_STDCALL;
1199 #else
1200 scheme_signal_error("%s: ABI not implemented: %V", who, sym);
1201 #endif
1202 } else {
1203 scheme_signal_error("%s: unknown ABI: %V", who, sym);
1204 }
1205 return 0; /* hush the compiler */
1206 }
1207
1208 /* helper macro */
1209 #define GET_ABI(name,n) \
1210 ((argc > (n)) ? sym_to_abi((name),argv[n]) : FFI_DEFAULT_ABI)
1211
1212 /*****************************************************************************/
1213 /* cstruct types */
1214
wrong_void(const char * who,Scheme_Object * list_element,int specifically_void,int which,int argc,Scheme_Object ** argv)1215 static void wrong_void(const char *who, Scheme_Object *list_element, int specifically_void,
1216 int which, int argc, Scheme_Object **argv)
1217 {
1218 intptr_t len;
1219 char *s;
1220
1221 if (argc > 1)
1222 s = scheme_make_arg_lines_string(" ", which, argc, argv, &len);
1223 else
1224 s = NULL;
1225
1226 if (list_element) {
1227 scheme_contract_error(who,
1228 (specifically_void
1229 ? "C type within list is based on _void"
1230 : "C type within list has a zero size"),
1231 "C type", 1, list_element,
1232 "list", 1, argv[which],
1233 s ? "other arguments" : NULL, 0, s,
1234 NULL);
1235 } else
1236 scheme_contract_error(who,
1237 (specifically_void
1238 ? "given C type is based on _void"
1239 : "given C type has a zero size"),
1240 "given C type", 1, argv[which],
1241 s ? "other arguments" : NULL, 0, s,
1242 NULL);
1243 }
1244
1245 /* (make-cstruct-type types [abi alignment malloc-mode]) -> ctype */
1246 /* This creates a new primitive type that is a struct. This type can be used
1247 * with cpointer objects, except that the contents is used rather than the
1248 * pointer value. Marshaling to lists or whatever should be done in Racket. */
1249 #define MYNAME "make-cstruct-type"
foreign_make_cstruct_type(int argc,Scheme_Object * argv[])1250 static Scheme_Object *foreign_make_cstruct_type(int argc, Scheme_Object *argv[])
1251 {
1252 Scheme_Object *p, *base;
1253 /* since ffi_type objects can be used in callbacks, they are allocated using
1254 * malloc so they don't move, and they are freed when the Scheme object is
1255 * GCed. */
1256 GC_CAN_IGNORE ffi_type **elements, *libffi_type, **dummy;
1257 ctype_struct *type;
1258 ffi_cif cif;
1259 int i, nargs, with_alignment;
1260 ffi_abi abi;
1261 Scheme_Object *fields = argv[0];
1262 nargs = scheme_proper_list_length(fields);
1263 if (nargs <= 0) scheme_wrong_contract(MYNAME, "(non-empty-listof ctype?)", 0, argc, argv);
1264 abi = GET_ABI(MYNAME,1);
1265 if (argc > 2) {
1266 if (!SCHEME_FALSEP(argv[2])) {
1267 if (!SAME_OBJ(argv[2], scheme_make_integer(1))
1268 && !SAME_OBJ(argv[2], scheme_make_integer(2))
1269 && !SAME_OBJ(argv[2], scheme_make_integer(4))
1270 && !SAME_OBJ(argv[2], scheme_make_integer(8))
1271 && !SAME_OBJ(argv[2], scheme_make_integer(16)))
1272 scheme_wrong_contract(MYNAME, "(or/c 1 2 4 8 16 #f)", 2, argc, argv);
1273 with_alignment = SCHEME_INT_VAL(argv[2]);
1274 } else
1275 with_alignment = 0;
1276 if (argc > 3) {
1277 if (!SAME_OBJ(argv[3], atomic_sym)) {
1278 (void)mode_to_allocator(MYNAME, argv[3]);
1279 fields = scheme_make_pair(argv[3], fields);
1280 }
1281 }
1282 } else
1283 with_alignment = 0;
1284
1285 /* allocate the type elements */
1286 elements = malloc((nargs+1) * sizeof(ffi_type*));
1287 elements[nargs] = NULL;
1288 for (i=0, p=argv[0]; i<nargs; i++, p=SCHEME_CDR(p)) {
1289 if (NULL == (base = get_ctype_base(SCHEME_CAR(p))))
1290 scheme_wrong_contract(MYNAME, "(non-empty-listof ctype?)", 0, argc, argv);
1291 if (CTYPE_PRIMLABEL(base) == FOREIGN_void)
1292 wrong_void(MYNAME, SCHEME_CAR(p), 1, 0, argc, argv);
1293 elements[i] = CTYPE_PRIMTYPE(base);
1294 if (with_alignment) {
1295 /* copy the type to set an alignment: */
1296 libffi_type = malloc(sizeof(ffi_type));
1297 memcpy(libffi_type, elements[i], sizeof(ffi_type));
1298 elements[i] = libffi_type;
1299 if (with_alignment < elements[i]->alignment)
1300 elements[i]->alignment = with_alignment;
1301 }
1302 }
1303
1304 /* allocate the new libffi type object */
1305 libffi_type = malloc(sizeof(ffi_type));
1306 libffi_type->size = 0;
1307 libffi_type->alignment = 0;
1308 libffi_type->type = FFI_TYPE_STRUCT;
1309 libffi_type->elements = elements;
1310 /* use ffi_prep_cif to set the size and alignment information */
1311 dummy = &libffi_type;
1312 if (ffi_prep_cif(&cif, abi, 1, &ffi_type_void, dummy) != FFI_OK)
1313 scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
1314 type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1315 type->so.type = ctype_tag;
1316 type->basetype = (fields);
1317 type->scheme_to_c = ((Scheme_Object*)libffi_type);
1318 type->c_to_scheme = ((Scheme_Object*)FOREIGN_struct);
1319 if (with_alignment)
1320 scheme_register_finalizer(type, free_libffi_type_two_layers, libffi_type, NULL, NULL);
1321 else
1322 scheme_register_finalizer(type, free_libffi_type, libffi_type, NULL, NULL);
1323 return (Scheme_Object*)type;
1324 }
1325 #undef MYNAME
1326
1327 /*****************************************************************************/
1328 /* array types */
1329
wrong_intptr(const char * who,int which,int argc,Scheme_Object ** argv)1330 static void wrong_intptr(const char *who, int which, int argc, Scheme_Object **argv)
1331 {
1332 if (!SCHEME_INTP(argv[which]) && !SCHEME_BIGNUMP(argv[which])) {
1333 scheme_wrong_contract(who, "exact-integer?", which, argc, argv);
1334 } else {
1335 intptr_t len;
1336 char *s;
1337
1338 if (argc > 1)
1339 s = scheme_make_arg_lines_string(" ", which, argc, argv, &len);
1340 else
1341 s = NULL;
1342
1343 scheme_contract_error(who,
1344 "given integer does not fit into the _intptr type",
1345 "given integer", 1, argv[which],
1346 s ? "other arguments" : NULL, 0, s,
1347 NULL);
1348 }
1349 }
1350
1351 #if defined(__aarch64__)
1352 # define SMALL_ARRAY_THRESHOLD 64
1353 #else
1354 # define SMALL_ARRAY_THRESHOLD 32
1355 #endif
1356
1357 /* (make-array-type type len) -> ctype */
1358 /* This creates a new primitive type that is an array. An array is the
1359 * same as a cpointer as an argument, but it behave differently within
1360 * a struct or for allocation. Marshaling to lists or whatever should
1361 * be done in Racket. */
1362 #define MYNAME "make-array-type"
foreign_make_array_type(int argc,Scheme_Object * argv[])1363 static Scheme_Object *foreign_make_array_type(int argc, Scheme_Object *argv[])
1364 {
1365 Scheme_Object *base, *basetype;
1366 GC_CAN_IGNORE ffi_type *libffi_type, **elements;
1367 ctype_struct *type;
1368 intptr_t len, size;
1369
1370 if (NULL == (base = get_ctype_base(argv[0])))
1371 scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
1372 if (!scheme_get_int_val(argv[1], &len) || (len < 0)) {
1373 if ((SCHEME_INTP(argv[1]) && SCHEME_INT_VAL(argv[1]) > 0)
1374 || (SCHEME_BIGNUMP(argv[1]) && SCHEME_BIGPOS(argv[1])))
1375 wrong_intptr(MYNAME, 1, argc, argv);
1376 else
1377 scheme_wrong_contract(MYNAME, "exact-nonnegative-integer?", 1, argc, argv);
1378 }
1379
1380 /* libffi doesn't seem to support array types, but we try to make
1381 libffi work anyway by making a structure type that is used when
1382 an array appears as a struct field. If the array size is 4 or
1383 less, or if the total size is SMALL_ARRAY_THRESHOLD bytes or
1384 less, then we make a full `elements' array, because the x86_64
1385 ABI always shifts to memory mode after 32 bytes and the AArch64
1386 ABI shifts after 64 bytes. */
1387
1388 /* Allocate the new libffi type object, which is only provided to
1389 libffi as a type for a structure field. When a FOREIGN_array
1390 type is used for a function argument or result, it is replaced
1391 with FOREIGN_pointer. We put FFI_TYPE_STRUCT in
1392 libffi_type->type and make an elements array that contains
1393 a single instance of the element type... which seems to work
1394 ok so far. */
1395 libffi_type = malloc(sizeof(ffi_type));
1396 size = mult_check_overflow(MYNAME, CTYPE_PRIMTYPE(base)->size, len);
1397 libffi_type->size = size;
1398 libffi_type->alignment = CTYPE_PRIMTYPE(base)->alignment;
1399 libffi_type->type = FFI_TYPE_STRUCT;
1400
1401 if ((libffi_type->size <= SMALL_ARRAY_THRESHOLD) || (len <= 4)) {
1402 int i;
1403 elements = malloc((len + 1) * sizeof(ffi_type*));
1404 for (i = 0; i < len; i++) {
1405 elements[i] = CTYPE_PRIMTYPE(base);
1406 }
1407 elements[len] = NULL;
1408 } else {
1409 elements = malloc(2 * sizeof(ffi_type*));
1410 elements[0] = CTYPE_PRIMTYPE(base);
1411 elements[1] = NULL;
1412 }
1413 libffi_type->elements = elements;
1414
1415 basetype = scheme_make_vector(2, argv[0]);
1416 SCHEME_VEC_ELS(basetype)[1] = argv[1];
1417
1418 type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1419 type->so.type = ctype_tag;
1420 type->basetype = (basetype);
1421 type->scheme_to_c = ((Scheme_Object*)libffi_type);
1422 type->c_to_scheme = ((Scheme_Object*)FOREIGN_array);
1423
1424 scheme_register_finalizer(type, free_libffi_type, libffi_type, NULL, NULL);
1425
1426 return (Scheme_Object*)type;
1427 }
1428 #undef MYNAME
1429
1430 /*****************************************************************************/
1431 /* union types */
1432
1433 static int all_float_types(GC_CAN_IGNORE ffi_type *libffi_type);
1434
1435 /* (make-union-type type ...+) -> ctype */
1436 /* This creates a new primitive type that is a union. All unions
1437 * behave like structs. Marshaling to lists or whatever should
1438 * be done in Racket. */
1439 #define MYNAME "make-union-type"
foreign_make_union_type(int argc,Scheme_Object * argv[])1440 static Scheme_Object *foreign_make_union_type(int argc, Scheme_Object *argv[])
1441 {
1442 Scheme_Object *base, *basetype;
1443 GC_CAN_IGNORE ffi_type *libffi_type, **elements = NULL;
1444 ctype_struct *type;
1445 int i, align = 1, a, sz = 0, count = 0, float_kinds = 0, float_kind;
1446 int some_non_floats = 0;
1447
1448 /* libffi doesn't support union types, so we try to make a
1449 reasonable approximation. The calling convention of a union type
1450 mostly likely depends on of the maximum size of all alternatives
1451 and whether it's floating-point or not. Synthesize a struct that
1452 is big enough and composed of only floats if the union
1453 alternative are only floats or integers otherwise. This is not
1454 guaranteed to be right, but it has a chance at working. */
1455
1456 /* find max required alignment and size: */
1457 for (i = 0; i < argc; i++) {
1458 if (NULL == (base = get_ctype_base(argv[i]))) {
1459 free(elements);
1460 scheme_wrong_contract(MYNAME, "ctype?", i, argc, argv);
1461 }
1462 a = CTYPE_PRIMTYPE(base)->alignment;
1463 if (a > align) align = a;
1464 a = CTYPE_PRIMTYPE(base)->size;
1465 if (sz < a) sz = a;
1466
1467 float_kind = all_float_types(CTYPE_PRIMTYPE(base));
1468 if (i == 0) float_kinds = float_kind;
1469 if (!float_kind || (float_kind != float_kinds))
1470 some_non_floats = 1;
1471 }
1472
1473 if (!sz)
1474 scheme_signal_error("empty union");
1475
1476 /* round size up to alignment: */
1477 if ((sz % align) != 0) {
1478 sz += (align - (sz % align));
1479 }
1480
1481 /* Synthesize element list */
1482 while (!elements) {
1483 if (count)
1484 elements = malloc((count+1) * sizeof(ffi_type*));
1485 count = 0;
1486
1487 if (some_non_floats) {
1488 /* build a struct out of integers */
1489 int remain_sz = sz;
1490 while (remain_sz >= sizeof(intptr_t)) {
1491 if (elements)
1492 elements[count] = &ffi_type_smzintptr;
1493 remain_sz -= sizeof(intptr_t);
1494 count++;
1495 }
1496 while (remain_sz >= sizeof(int)) {
1497 if (elements)
1498 elements[count] = &ffi_type_sint32;
1499 remain_sz -= sizeof(int);
1500 count++;
1501 }
1502 while (remain_sz >= sizeof(short)) {
1503 if (elements)
1504 elements[count] = &ffi_type_sint16;
1505 remain_sz -= sizeof(short);
1506 count++;
1507 }
1508 while (remain_sz) {
1509 if (elements)
1510 elements[count] = &ffi_type_sint8;
1511 remain_sz -= 1;
1512 count++;
1513 }
1514 /* remain_sz should be 0 at this point */
1515 } else {
1516 /* build a struct out of doubles and floats */
1517 int remain_sz = sz;
1518 while (remain_sz >= sizeof(double)) {
1519 if (elements)
1520 elements[count] = &ffi_type_double;
1521 remain_sz -= sizeof(double);
1522 count++;
1523 }
1524 while (remain_sz >= sizeof(float)) {
1525 if (elements)
1526 elements[count] = &ffi_type_float;
1527 remain_sz -= sizeof(float);
1528 count++;
1529 }
1530 /* remain_sz should be 0 at this point */
1531 }
1532 }
1533
1534 elements[count] = NULL;
1535
1536 /* Allocate the new libffi type object. */
1537 libffi_type = malloc(sizeof(ffi_type));
1538 libffi_type->size = sz;
1539 libffi_type->alignment = align;
1540 libffi_type->type = FFI_TYPE_STRUCT;
1541 libffi_type->elements = elements;
1542
1543 basetype = scheme_box(scheme_build_list(argc, argv));
1544
1545 type = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
1546 type->so.type = ctype_tag;
1547 type->basetype = (basetype);
1548 type->scheme_to_c = ((Scheme_Object*)libffi_type);
1549 type->c_to_scheme = ((Scheme_Object*)FOREIGN_union);
1550
1551 scheme_register_finalizer(type, free_libffi_type, libffi_type, NULL, NULL);
1552
1553 return (Scheme_Object*)type;
1554 }
1555 #undef MYNAME
1556
all_float_types_k(void)1557 static Scheme_Object *all_float_types_k(void)
1558 {
1559 Scheme_Thread *p = scheme_current_thread;
1560 int r;
1561 r = all_float_types((ffi_type *)p->ku.k.i1);
1562 return scheme_make_integer(r);
1563 }
1564
1565 #if defined(__arm__) || defined(__thumb__) || defined(__aarch64__)
1566 /* Arm: uniform floats must be the same type */
1567 # define FLOAT_KIND_DOUBLE 1
1568 # define FLOAT_KIND_FLOAT 2
1569 # define FLOAT_KIND_EXT 3
1570 #else
1571 /* Other: different kinds of floats are treated the same */
1572 # define FLOAT_KIND_DOUBLE 1
1573 # define FLOAT_KIND_FLOAT 1
1574 # define FLOAT_KIND_EXT 1
1575 #endif
1576
all_float_types(GC_CAN_IGNORE ffi_type * libffi_type)1577 static int all_float_types(GC_CAN_IGNORE ffi_type *libffi_type)
1578 {
1579 {
1580 # include "mzstkchk.h"
1581 {
1582 Scheme_Thread *p = scheme_current_thread;
1583 Scheme_Object *r;
1584 p->ku.k.i1 = (intptr_t)libffi_type;
1585 r = scheme_handle_stack_overflow(all_float_types_k);
1586 return SCHEME_INT_VAL(r);
1587 }
1588 }
1589
1590 if (libffi_type == &ffi_type_double)
1591 return FLOAT_KIND_DOUBLE;
1592 if (libffi_type == &ffi_type_float)
1593 return FLOAT_KIND_FLOAT;
1594 if (libffi_type == &ffi_type_longdouble)
1595 return FLOAT_KIND_EXT;
1596
1597 if (libffi_type->type == FFI_TYPE_STRUCT) {
1598 int i, kind = 0, k;
1599 for (i = 0; libffi_type->elements[i]; i++) {
1600 k = all_float_types(libffi_type->elements[i]);
1601 if (!k)
1602 return 0;
1603 if (!i)
1604 kind = k;
1605 else if (kind != k)
1606 return 0;
1607 }
1608 return kind;
1609 }
1610
1611 return 0;
1612 }
1613
1614 /*****************************************************************************/
1615 /* Callback type */
1616
1617 /* ffi-callback structure definition */
1618 static Scheme_Type ffi_callback_tag;
1619 typedef struct ffi_callback_struct {
1620 Scheme_Object so;
1621 NON_GCBALE_PTR(void) callback;
1622 Scheme_Object* proc;
1623 Scheme_Object* itypes;
1624 Scheme_Object* otype;
1625 Scheme_Object* sync;
1626 } ffi_callback_struct;
1627 #define SCHEME_FFICALLBACKP(x) (SCHEME_TYPE(x)==ffi_callback_tag)
1628 #define MYNAME "ffi-callback?"
foreign_ffi_callback_p(int argc,Scheme_Object * argv[])1629 static Scheme_Object *foreign_ffi_callback_p(int argc, Scheme_Object *argv[])
1630 {
1631 return SCHEME_FFICALLBACKP(argv[0]) ? scheme_true : scheme_false;
1632 }
1633 #undef MYNAME
1634 /* 3m stuff for ffi_callback */
1635 #ifdef MZ_PRECISE_GC
1636 START_XFORM_SKIP;
ffi_callback_SIZE(void * p)1637 int ffi_callback_SIZE(void *p) {
1638 return gcBYTES_TO_WORDS(sizeof(ffi_callback_struct));
1639 }
ffi_callback_MARK(void * p)1640 int ffi_callback_MARK(void *p) {
1641 ffi_callback_struct *s = (ffi_callback_struct *)p;
1642 gcMARK(s->proc);
1643 gcMARK(s->itypes);
1644 gcMARK(s->otype);
1645 gcMARK(s->sync);
1646 return gcBYTES_TO_WORDS(sizeof(ffi_callback_struct));
1647 }
ffi_callback_FIXUP(void * p)1648 int ffi_callback_FIXUP(void *p) {
1649 ffi_callback_struct *s = (ffi_callback_struct *)p;
1650 gcFIXUP(s->proc);
1651 gcFIXUP(s->itypes);
1652 gcFIXUP(s->otype);
1653 gcFIXUP(s->sync);
1654 return gcBYTES_TO_WORDS(sizeof(ffi_callback_struct));
1655 }
1656 END_XFORM_SKIP;
1657 #endif /* pointer to another ffi-callback for a curried callback */
1658
1659 /* The sync field:
1660 * NULL => non-atomic mode
1661 * #t => atomic mode, no sync proc
1662 * proc => non-atomic mode, sync proc
1663 * (box proc) => atomic mode, sync proc
1664 */
1665
1666 /*****************************************************************************/
1667 /* Pointer objects */
1668 /* use cpointer (with a NULL tag when creating), #f for NULL */
1669
1670 #define SCHEME_FFIANYPTRP(x) \
1671 (SCHEME_FALSEP(x) || SCHEME_CPTRP(x) || SCHEME_FFIOBJP(x) || \
1672 SCHEME_BYTE_STRINGP(x) || SCHEME_FFICALLBACKP(x))
1673 #define SCHEME_FFIANYPTR_VAL(x) \
1674 (SCHEME_CPTRP(x) ? SCHEME_CPTR_VAL(x) : \
1675 (SCHEME_FALSEP(x) ? NULL : \
1676 (SCHEME_FFIOBJP(x) ? (((ffi_obj_struct*)x)->obj) : \
1677 (SCHEME_BYTE_STRINGP(x) ? SCHEME_BYTE_STR_VAL(x) : \
1678 (SCHEME_FFICALLBACKP(x) ? ((ffi_callback_struct *)x)->callback : \
1679 NULL)))))
1680 #define SCHEME_FFIANYPTR_OFFSET(x) \
1681 (SCHEME_CPTRP(x) ? SCHEME_CPTR_OFFSET(x) : 0)
1682 #define SCHEME_FFIANYPTR_OFFSETVAL(x) \
1683 W_OFFSET(SCHEME_FFIANYPTR_VAL(x), SCHEME_FFIANYPTR_OFFSET(x))
1684
1685 #define SCHEME_CPOINTER_W_OFFSET_P(x) \
1686 (SCHEME_CPTRP(x) && SCHEME_CPTR_HAS_OFFSET(x))
1687
1688 #define scheme_make_foreign_cpointer(x) \
1689 ((x==NULL)?scheme_false:scheme_make_cptr(x,NULL))
1690
1691 #define scheme_make_foreign_offset_cpointer(x, delta) \
1692 ((delta == 0) ? scheme_make_foreign_cpointer(x) : scheme_make_offset_cptr(x,delta,NULL))
1693
1694 #define scheme_make_foreign_external_cpointer(x) \
1695 ((x==NULL)?scheme_false:scheme_make_external_cptr(x,NULL))
1696
1697 #define scheme_make_foreign_offset_external_cpointer(x, delta) \
1698 ((delta == 0) ? scheme_make_foreign_external_cpointer(x) : scheme_make_offset_external_cptr(x,delta,NULL))
1699
check_cpointer_property(Scheme_Object * v)1700 static int check_cpointer_property(Scheme_Object *v)
1701 {
1702 if (SCHEME_CHAPERONE_STRUCTP(v)
1703 && scheme_struct_type_property_ref(scheme_cpointer_property, v))
1704 return 1;
1705 else
1706 return 0;
1707 }
1708
unwrap_cpointer_property_slow(Scheme_Object * orig_v)1709 static Scheme_Object *unwrap_cpointer_property_slow(Scheme_Object *orig_v)
1710 {
1711 Scheme_Object *v = orig_v, *val;
1712 int must = 0;
1713
1714 while (1) {
1715 if (SCHEME_CHAPERONE_STRUCTP(v)) {
1716 val = scheme_struct_type_property_ref(scheme_cpointer_property, v);
1717 if (val) {
1718 if (SCHEME_INTP(val))
1719 v = scheme_struct_ref(v, SCHEME_INT_VAL(val));
1720 else if (SCHEME_PROCP(val)) {
1721 Scheme_Object *a[1];
1722 a[0] = v;
1723 v = _scheme_apply(val, 1, a);
1724 } else
1725 v = val;
1726 must = 1;
1727 } else
1728 break;
1729 } else
1730 break;
1731 }
1732
1733 if (must && !SCHEME_FFIANYPTRP(v)) {
1734 scheme_wrong_contract("prop:cpointer accessor", "cpointer?", 0, -1, &v);
1735 return NULL;
1736 }
1737
1738 return v;
1739 }
1740
unwrap_cpointer_property(Scheme_Object * v)1741 static Scheme_Object *unwrap_cpointer_property(Scheme_Object *v)
1742 {
1743 if (SCHEME_FFIANYPTRP(v))
1744 return v;
1745 else
1746 return unwrap_cpointer_property_slow(v);
1747 }
1748
scheme_is_cpointer(Scheme_Object * cp)1749 int scheme_is_cpointer(Scheme_Object *cp) {
1750 return (SCHEME_FFIANYPTRP(cp) || check_cpointer_property(cp));
1751 }
1752
1753 #define MYNAME "cpointer?"
foreign_cpointer_p(int argc,Scheme_Object * argv[])1754 static Scheme_Object *foreign_cpointer_p(int argc, Scheme_Object *argv[])
1755 {
1756 return (scheme_is_cpointer(argv[0])
1757 ? scheme_true
1758 : scheme_false);
1759 }
1760 #undef MYNAME
1761
1762 #define MYNAME "cpointer-tag"
foreign_cpointer_tag(int argc,Scheme_Object * argv[])1763 static Scheme_Object *foreign_cpointer_tag(int argc, Scheme_Object *argv[])
1764 {
1765 Scheme_Object *tag = NULL;
1766 Scheme_Object *cp;
1767 cp = unwrap_cpointer_property(argv[0]);
1768 if (!SCHEME_FFIANYPTRP(cp))
1769 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
1770 if (SCHEME_CPTRP(cp)) tag = SCHEME_CPTR_TYPE(cp);
1771 return (tag == NULL) ? scheme_false : tag;
1772 }
1773 #undef MYNAME
1774
scheme_cpointer_tag(Scheme_Object * ptr)1775 Scheme_Object *scheme_cpointer_tag(Scheme_Object *ptr)
1776 {
1777 Scheme_Object *a[1];
1778 a[0] = ptr;
1779 return foreign_cpointer_tag(1, a);
1780 }
1781
1782 #define MYNAME "set-cpointer-tag!"
foreign_set_cpointer_tag_bang(int argc,Scheme_Object * argv[])1783 static Scheme_Object *foreign_set_cpointer_tag_bang(int argc, Scheme_Object *argv[])
1784 {
1785 Scheme_Object *cp;
1786 cp = unwrap_cpointer_property(argv[0]);
1787 if (!SCHEME_CPTRP(cp))
1788 scheme_wrong_contract(MYNAME, "proper-cpointer?", 0, argc, argv);
1789 SCHEME_CPTR_TYPE(cp) = argv[1];
1790 return scheme_void;
1791 }
1792 #undef MYNAME
1793
scheme_set_cpointer_tag(Scheme_Object * ptr,Scheme_Object * val)1794 void scheme_set_cpointer_tag(Scheme_Object *ptr, Scheme_Object *val)
1795 {
1796 Scheme_Object *a[2];
1797 a[0] = ptr;
1798 a[1] = val;
1799 (void)foreign_set_cpointer_tag_bang(2, a);
1800 }
1801
1802 #define MYNAME "cpointer-gcable?"
foreign_cpointer_gcable_p(int argc,Scheme_Object * argv[])1803 static Scheme_Object *foreign_cpointer_gcable_p(int argc, Scheme_Object *argv[])
1804 {
1805 Scheme_Object *cp;
1806 cp = unwrap_cpointer_property(argv[0]);
1807 if (SCHEME_CPTRP(cp)) {
1808 return ((SCHEME_CPTR_FLAGS(cp) & 0x1)
1809 ? scheme_false
1810 : scheme_true);
1811 } else if (SCHEME_FALSEP(cp)
1812 || SCHEME_FFIOBJP(cp)
1813 || SCHEME_FFICALLBACKP(cp))
1814 return scheme_false;
1815 else if (SCHEME_BYTE_STRINGP(cp))
1816 return scheme_true;
1817 else {
1818 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
1819 return NULL;
1820 }
1821 }
1822 #undef MYNAME
1823
scheme_extract_pointer(Scheme_Object * v)1824 void *scheme_extract_pointer(Scheme_Object *v) {
1825 return SCHEME_FFIANYPTR_OFFSETVAL(v);
1826 }
1827
1828 /*****************************************************************************/
1829 /* Racket<-->C conversions */
1830
1831 /* On big endian machines we need to know whether we're pulling a value from an
1832 * argument location where it always takes a whole word or straight from a
1833 * memory location -- deal with it via a C2SCHEME macro wrapper that is used
1834 * for both the function definition and calls */
1835 #ifdef SCHEME_BIG_ENDIAN
1836 #define C2SCHEME(ap,typ,src,delta,argsloc,gcsrc) c_to_scheme(ap,typ,src,delta,argsloc,gcsrc)
1837 #define REF_CTYPE(ctype) (((sizeof(ctype)<sizeof(intptr_t)) && args_loc) \
1838 ? ((ctype)(((intptr_t*)W_OFFSET(src,delta))[0])) \
1839 : (((ctype *)W_OFFSET(src,delta))[0]))
1840 #else
1841 #define C2SCHEME(ap,typ,src,delta,argsloc,gcsrc) c_to_scheme(ap,typ,src,delta,gcsrc)
1842 #define REF_CTYPE(ctype) (((ctype *)W_OFFSET(src,delta))[0])
1843 #endif
1844
C2SCHEME(Scheme_Object * already_ptr,Scheme_Object * type,void * src,intptr_t delta,int args_loc,int gcsrc)1845 static Scheme_Object *C2SCHEME(Scheme_Object *already_ptr, Scheme_Object *type, void *src,
1846 intptr_t delta, int args_loc, int gcsrc)
1847 {
1848 Scheme_Object *res;
1849 if (!SCHEME_CTYPEP(type))
1850 scheme_wrong_contract("C->Racket", "ctype?", 0, 1, &type);
1851 if (CTYPE_USERP(type)) {
1852 res = C2SCHEME(already_ptr, CTYPE_BASETYPE(type), src, delta, args_loc, gcsrc);
1853 if (SCHEME_FALSEP(CTYPE_USER_C2S(type)))
1854 return res;
1855 else
1856 return _scheme_apply(CTYPE_USER_C2S(type), 1, (Scheme_Object**)(&res));
1857 } else if (CTYPE_PRIMLABEL(type) == FOREIGN_fpointer) {
1858 if (already_ptr) return already_ptr;
1859 return scheme_make_foreign_external_cpointer(*(void **)W_OFFSET(src, delta));
1860 } else switch (CTYPE_PRIMLABEL(type)) {
1861 case FOREIGN_void: return scheme_void;
1862 case FOREIGN_int8: return scheme_make_integer(REF_CTYPE(Tsint8));
1863 case FOREIGN_uint8: return scheme_make_integer(REF_CTYPE(Tuint8));
1864 case FOREIGN_int16: return scheme_make_integer(REF_CTYPE(Tsint16));
1865 case FOREIGN_uint16: return scheme_make_integer(REF_CTYPE(Tuint16));
1866 case FOREIGN_int32: return scheme_make_realinteger_value(REF_CTYPE(Tsint32));
1867 case FOREIGN_uint32: return scheme_make_realinteger_value_from_unsigned(REF_CTYPE(Tuint32));
1868 case FOREIGN_int64: return scheme_make_integer_value_from_long_long(REF_CTYPE(Tsint64));
1869 case FOREIGN_uint64: return scheme_make_integer_value_from_unsigned_long_long(REF_CTYPE(Tuint64));
1870 case FOREIGN_fixint: return scheme_make_integer(REF_CTYPE(Tsint32));
1871 case FOREIGN_ufixint: return scheme_make_integer_from_unsigned(REF_CTYPE(Tuint32));
1872 case FOREIGN_fixnum: return scheme_make_integer(REF_CTYPE(intptr_t));
1873 case FOREIGN_ufixnum: return scheme_make_integer_from_unsigned(REF_CTYPE(uintptr_t));
1874 case FOREIGN_float: return scheme_make_double(REF_CTYPE(float));
1875 case FOREIGN_double: return scheme_make_double(REF_CTYPE(double));
1876 case FOREIGN_longdouble: return scheme_make_maybe_long_double(REF_CTYPE(mz_long_double));
1877 case FOREIGN_doubleS: return scheme_make_double(REF_CTYPE(double));
1878 case FOREIGN_bool: return (REF_CTYPE(int)?scheme_true:scheme_false);
1879 case FOREIGN_stdbool: return (REF_CTYPE(stdbool)?scheme_true:scheme_false);
1880 case FOREIGN_string_ucs_4: return scheme_make_char_string_without_copying(REF_CTYPE(mzchar*));
1881 case FOREIGN_string_utf_16: return utf16_pointer_to_ucs4_string(REF_CTYPE(unsigned short*));
1882 case FOREIGN_bytes: return (REF_CTYPE(char*)==NULL)?scheme_false:scheme_make_byte_string_without_copying(REF_CTYPE(char*));
1883 case FOREIGN_path: return (REF_CTYPE(char*)==NULL)?scheme_false:scheme_make_path_without_copying(REF_CTYPE(char*));
1884 case FOREIGN_symbol: return scheme_intern_symbol(REF_CTYPE(char*));
1885 case FOREIGN_pointer: return scheme_make_foreign_external_cpointer(REF_CTYPE(void*));
1886 case FOREIGN_gcpointer: return scheme_make_foreign_cpointer(REF_CTYPE(void*));
1887 case FOREIGN_scheme: return REF_CTYPE(Scheme_Object*);
1888 case FOREIGN_fpointer: return (REF_CTYPE(void*));
1889 case FOREIGN_struct:
1890 case FOREIGN_array:
1891 case FOREIGN_union:
1892 if (gcsrc)
1893 return scheme_make_foreign_offset_cpointer(src, delta);
1894 else
1895 return scheme_make_foreign_offset_external_cpointer(src, delta);
1896 default: scheme_signal_error("corrupt foreign type: %V", type);
1897 }
1898 return NULL; /* hush the compiler */
1899 }
1900 #undef REF_CTYPE
1901
wrong_value(const char * who,const char * type,Scheme_Object * val)1902 static void *wrong_value(const char *who, const char *type, Scheme_Object *val)
1903 {
1904 scheme_contract_error(who,
1905 "given value does not fit primitive C type",
1906 "C type", 0, type,
1907 "given value", 1, val,
1908 NULL);
1909 return NULL;
1910 }
1911
1912 /* On big endian machines we need to know whether we're pulling a value from an
1913 * argument location where it always takes a whole word or straight from a
1914 * memory location -- deal with it as above, via a SCHEME2C macro wrapper that
1915 * is used for both the function definition and calls, but the actual code in
1916 * the function is different: in the relevant cases zero an int and offset the
1917 * ptr */
1918
1919 /* Usually writes the C object to dst and returns NULL. When basetype_p is not
1920 * NULL, then any pointer value (any pointer or a struct or array) is returned, and the
1921 * basetype_p is set to the corresponding number tag. If basetype_p is NULL,
1922 * then a struct or array value will be *copied* into dst. */
SCHEME2C(const char * who,Scheme_Object * type,void * dst,intptr_t delta,Scheme_Object * val,GC_CAN_IGNORE intptr_t * basetype_p,GC_CAN_IGNORE intptr_t * _offset,int ret_loc)1923 static void* SCHEME2C(const char *who,
1924 Scheme_Object *type, void *dst, intptr_t delta,
1925 Scheme_Object *val, GC_CAN_IGNORE intptr_t *basetype_p, GC_CAN_IGNORE intptr_t *_offset,
1926 int ret_loc)
1927 {
1928 /* redundant check:
1929 if (!SCHEME_CTYPEP(type))
1930 scheme_wrong_contract(who, "ctype?", 0, 1, &type); */
1931 while (CTYPE_USERP(type)) {
1932 GC_CAN_IGNORE Scheme_Object *f = CTYPE_USER_S2C(type);
1933 if (!SCHEME_FALSEP(f)) {
1934 if (SAME_TYPE(SCHEME_TYPE(f), scheme_native_closure_type))
1935 val = _scheme_apply_native(f, 1, (Scheme_Object**)(&val));
1936 else
1937 val = _scheme_apply(f, 1, (Scheme_Object**)(&val));
1938 }
1939 type = CTYPE_BASETYPE(type);
1940 }
1941 if (CTYPE_PRIMLABEL(type) == FOREIGN_fpointer) {
1942 val = unwrap_cpointer_property(val);
1943 /* No need for the SET_CTYPE trick for pointers. */
1944 if (SCHEME_FFICALLBACKP(val))
1945 ((void**)W_OFFSET(dst,delta))[0] = ((ffi_callback_struct*)val)->callback;
1946 else if (SCHEME_CPTRP(val))
1947 ((void**)W_OFFSET(dst,delta))[0] = SCHEME_CPTR_VAL(val);
1948 else if (SCHEME_FFIOBJP(val))
1949 ((void**)W_OFFSET(dst,delta))[0] = ((ffi_obj_struct*)val)->obj;
1950 else if (SCHEME_FALSEP(val))
1951 ((void**)W_OFFSET(dst,delta))[0] = NULL;
1952 else /* ((void**)W_OFFSET(dst,delta))[0] = val; */
1953 return wrong_value(who, "_fpointer", val);
1954 } else switch (CTYPE_PRIMLABEL(type)) {
1955 case FOREIGN_void:
1956 if (!ret_loc) return wrong_value(who, "_void", val);;
1957 break;
1958 case FOREIGN_int8:
1959 # ifdef SCHEME_BIG_ENDIAN
1960 if (sizeof(Tsint8)<sizeof(intptr_t) && ret_loc) {
1961 ((int*)W_OFFSET(dst,delta))[0] = 0;
1962 delta += (sizeof(intptr_t)-sizeof(Tsint8));
1963 }
1964 # endif /* SCHEME_BIG_ENDIAN */
1965 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
1966 if (sizeof(Tsint8)<sizeof(intptr_t) && ret_loc) {
1967 ((int*)W_OFFSET(dst,delta))[0] = 0;
1968 }
1969 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
1970 if (!(get_byte_val(val,&(((Tsint8*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int8", val);;
1971 return NULL;
1972 case FOREIGN_uint8:
1973 # ifdef SCHEME_BIG_ENDIAN
1974 if (sizeof(Tuint8)<sizeof(intptr_t) && ret_loc) {
1975 ((int*)W_OFFSET(dst,delta))[0] = 0;
1976 delta += (sizeof(intptr_t)-sizeof(Tuint8));
1977 }
1978 # endif /* SCHEME_BIG_ENDIAN */
1979 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
1980 if (sizeof(Tuint8)<sizeof(intptr_t) && ret_loc) {
1981 ((int*)W_OFFSET(dst,delta))[0] = 0;
1982 }
1983 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
1984 if (!(get_ubyte_val(val,&(((Tuint8*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint8", val);;
1985 return NULL;
1986 case FOREIGN_int16:
1987 # ifdef SCHEME_BIG_ENDIAN
1988 if (sizeof(Tsint16)<sizeof(intptr_t) && ret_loc) {
1989 ((int*)W_OFFSET(dst,delta))[0] = 0;
1990 delta += (sizeof(intptr_t)-sizeof(Tsint16));
1991 }
1992 # endif /* SCHEME_BIG_ENDIAN */
1993 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
1994 if (sizeof(Tsint16)<sizeof(intptr_t) && ret_loc) {
1995 ((int*)W_OFFSET(dst,delta))[0] = 0;
1996 }
1997 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
1998 if (!(get_short_val(val,&(((Tsint16*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int16", val);;
1999 return NULL;
2000 case FOREIGN_uint16:
2001 # ifdef SCHEME_BIG_ENDIAN
2002 if (sizeof(Tuint16)<sizeof(intptr_t) && ret_loc) {
2003 ((int*)W_OFFSET(dst,delta))[0] = 0;
2004 delta += (sizeof(intptr_t)-sizeof(Tuint16));
2005 }
2006 # endif /* SCHEME_BIG_ENDIAN */
2007 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2008 if (sizeof(Tuint16)<sizeof(intptr_t) && ret_loc) {
2009 ((int*)W_OFFSET(dst,delta))[0] = 0;
2010 }
2011 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2012 if (!(get_ushort_val(val,&(((Tuint16*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint16", val);;
2013 return NULL;
2014 case FOREIGN_int32:
2015 # ifdef SCHEME_BIG_ENDIAN
2016 if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2017 ((int*)W_OFFSET(dst,delta))[0] = 0;
2018 delta += (sizeof(intptr_t)-sizeof(Tsint32));
2019 }
2020 # endif /* SCHEME_BIG_ENDIAN */
2021 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2022 if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2023 ((int*)W_OFFSET(dst,delta))[0] = 0;
2024 }
2025 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2026 if (!(scheme_get_realint_val(val,&(((Tsint32*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int32", val);;
2027 return NULL;
2028 case FOREIGN_uint32:
2029 # ifdef SCHEME_BIG_ENDIAN
2030 if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2031 ((int*)W_OFFSET(dst,delta))[0] = 0;
2032 delta += (sizeof(intptr_t)-sizeof(Tuint32));
2033 }
2034 # endif /* SCHEME_BIG_ENDIAN */
2035 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2036 if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2037 ((int*)W_OFFSET(dst,delta))[0] = 0;
2038 }
2039 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2040 if (!(scheme_get_unsigned_realint_val(val,&(((Tuint32*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint32", val);;
2041 return NULL;
2042 case FOREIGN_int64:
2043 # ifdef SCHEME_BIG_ENDIAN
2044 if (sizeof(Tsint64)<sizeof(intptr_t) && ret_loc) {
2045 ((int*)W_OFFSET(dst,delta))[0] = 0;
2046 delta += (sizeof(intptr_t)-sizeof(Tsint64));
2047 }
2048 # endif /* SCHEME_BIG_ENDIAN */
2049 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2050 if (sizeof(Tsint64)<sizeof(intptr_t) && ret_loc) {
2051 ((int*)W_OFFSET(dst,delta))[0] = 0;
2052 }
2053 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2054 if (!(scheme_get_long_long_val(val,&(((Tsint64*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_int64", val);;
2055 return NULL;
2056 case FOREIGN_uint64:
2057 # ifdef SCHEME_BIG_ENDIAN
2058 if (sizeof(Tuint64)<sizeof(intptr_t) && ret_loc) {
2059 ((int*)W_OFFSET(dst,delta))[0] = 0;
2060 delta += (sizeof(intptr_t)-sizeof(Tuint64));
2061 }
2062 # endif /* SCHEME_BIG_ENDIAN */
2063 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2064 if (sizeof(Tuint64)<sizeof(intptr_t) && ret_loc) {
2065 ((int*)W_OFFSET(dst,delta))[0] = 0;
2066 }
2067 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2068 if (!(scheme_get_unsigned_long_long_val(val,&(((Tuint64*)W_OFFSET(dst,delta))[0])))) return wrong_value(who, "_uint64", val);;
2069 return NULL;
2070 case FOREIGN_fixint:
2071 # ifdef SCHEME_BIG_ENDIAN
2072 if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2073 ((int*)W_OFFSET(dst,delta))[0] = 0;
2074 delta += (sizeof(intptr_t)-sizeof(Tsint32));
2075 }
2076 # endif /* SCHEME_BIG_ENDIAN */
2077 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2078 if (sizeof(Tsint32)<sizeof(intptr_t) && ret_loc) {
2079 ((int*)W_OFFSET(dst,delta))[0] = 0;
2080 }
2081 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2082
2083 if (SCHEME_INTP(val)) {
2084 Tsint32 tmp;
2085 tmp = MZ_TYPE_CAST(Tsint32, SCHEME_INT_VAL(val));
2086 (((Tsint32*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2087 } else {
2088 return wrong_value(who, "_fixint", val);;
2089 return NULL; /* hush the compiler */
2090 }
2091 case FOREIGN_ufixint:
2092 # ifdef SCHEME_BIG_ENDIAN
2093 if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2094 ((int*)W_OFFSET(dst,delta))[0] = 0;
2095 delta += (sizeof(intptr_t)-sizeof(Tuint32));
2096 }
2097 # endif /* SCHEME_BIG_ENDIAN */
2098 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2099 if (sizeof(Tuint32)<sizeof(intptr_t) && ret_loc) {
2100 ((int*)W_OFFSET(dst,delta))[0] = 0;
2101 }
2102 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2103
2104 if (SCHEME_INTP(val)) {
2105 Tuint32 tmp;
2106 tmp = MZ_TYPE_CAST(Tuint32, SCHEME_UINT_VAL(val));
2107 (((Tuint32*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2108 } else {
2109 return wrong_value(who, "_ufixint", val);;
2110 return NULL; /* hush the compiler */
2111 }
2112 case FOREIGN_fixnum:
2113 # ifdef SCHEME_BIG_ENDIAN
2114 if (sizeof(intptr_t)<sizeof(intptr_t) && ret_loc) {
2115 ((int*)W_OFFSET(dst,delta))[0] = 0;
2116 delta += (sizeof(intptr_t)-sizeof(intptr_t));
2117 }
2118 # endif /* SCHEME_BIG_ENDIAN */
2119 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2120 if (sizeof(intptr_t)<sizeof(intptr_t) && ret_loc) {
2121 ((int*)W_OFFSET(dst,delta))[0] = 0;
2122 }
2123 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2124
2125 if (SCHEME_INTP(val)) {
2126 intptr_t tmp;
2127 tmp = MZ_TYPE_CAST(intptr_t, SCHEME_INT_VAL(val));
2128 (((intptr_t*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2129 } else {
2130 return wrong_value(who, "_fixnum", val);;
2131 return NULL; /* hush the compiler */
2132 }
2133 case FOREIGN_ufixnum:
2134 # ifdef SCHEME_BIG_ENDIAN
2135 if (sizeof(uintptr_t)<sizeof(intptr_t) && ret_loc) {
2136 ((int*)W_OFFSET(dst,delta))[0] = 0;
2137 delta += (sizeof(intptr_t)-sizeof(uintptr_t));
2138 }
2139 # endif /* SCHEME_BIG_ENDIAN */
2140 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2141 if (sizeof(uintptr_t)<sizeof(intptr_t) && ret_loc) {
2142 ((int*)W_OFFSET(dst,delta))[0] = 0;
2143 }
2144 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2145
2146 if (SCHEME_INTP(val)) {
2147 uintptr_t tmp;
2148 tmp = MZ_TYPE_CAST(uintptr_t, SCHEME_UINT_VAL(val));
2149 (((uintptr_t*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2150 } else {
2151 return wrong_value(who, "_ufixnum", val);;
2152 return NULL; /* hush the compiler */
2153 }
2154 case FOREIGN_float:
2155 # ifdef SCHEME_BIG_ENDIAN
2156 if (sizeof(float)<sizeof(intptr_t) && ret_loc) {
2157 ((int*)W_OFFSET(dst,delta))[0] = 0;
2158 delta += (sizeof(intptr_t)-sizeof(float));
2159 }
2160 # endif /* SCHEME_BIG_ENDIAN */
2161 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2162 if (sizeof(float)<sizeof(intptr_t) && ret_loc) {
2163 ((int*)W_OFFSET(dst,delta))[0] = 0;
2164 }
2165 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2166
2167 if (SCHEME_FLOATP(val)) {
2168 float tmp;
2169 tmp = MZ_TYPE_CAST(float, SCHEME_FLOAT_VAL(val));
2170 (((float*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2171 } else {
2172 return wrong_value(who, "_float", val);;
2173 return NULL; /* hush the compiler */
2174 }
2175 case FOREIGN_double:
2176 # ifdef SCHEME_BIG_ENDIAN
2177 if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2178 ((int*)W_OFFSET(dst,delta))[0] = 0;
2179 delta += (sizeof(intptr_t)-sizeof(double));
2180 }
2181 # endif /* SCHEME_BIG_ENDIAN */
2182 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2183 if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2184 ((int*)W_OFFSET(dst,delta))[0] = 0;
2185 }
2186 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2187
2188 if (SCHEME_FLOATP(val)) {
2189 double tmp;
2190 tmp = MZ_TYPE_CAST(double, SCHEME_FLOAT_VAL(val));
2191 (((double*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2192 } else {
2193 return wrong_value(who, "_double", val);;
2194 return NULL; /* hush the compiler */
2195 }
2196 case FOREIGN_longdouble:
2197 # ifdef SCHEME_BIG_ENDIAN
2198 if (sizeof(mz_long_double)<sizeof(intptr_t) && ret_loc) {
2199 ((int*)W_OFFSET(dst,delta))[0] = 0;
2200 delta += (sizeof(intptr_t)-sizeof(mz_long_double));
2201 }
2202 # endif /* SCHEME_BIG_ENDIAN */
2203 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2204 if (sizeof(mz_long_double)<sizeof(intptr_t) && ret_loc) {
2205 ((int*)W_OFFSET(dst,delta))[0] = 0;
2206 }
2207 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2208
2209 if (SCHEME_LONG_DBLP(val)) {
2210 mz_long_double tmp;
2211 tmp = MZ_NO_TYPE_CAST(mz_long_double, SCHEME_MAYBE_LONG_DBL_VAL(val));
2212 (((mz_long_double*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2213 } else {
2214 return wrong_value(who, "_longdouble", val);;
2215 return NULL; /* hush the compiler */
2216 }
2217 case FOREIGN_doubleS:
2218 # ifdef SCHEME_BIG_ENDIAN
2219 if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2220 ((int*)W_OFFSET(dst,delta))[0] = 0;
2221 delta += (sizeof(intptr_t)-sizeof(double));
2222 }
2223 # endif /* SCHEME_BIG_ENDIAN */
2224 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2225 if (sizeof(double)<sizeof(intptr_t) && ret_loc) {
2226 ((int*)W_OFFSET(dst,delta))[0] = 0;
2227 }
2228 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2229
2230 if (SCHEME_REALP(val)) {
2231 double tmp;
2232 tmp = MZ_TYPE_CAST(double, scheme_real_to_double(val));
2233 (((double*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2234 } else {
2235 return wrong_value(who, "_double*", val);;
2236 return NULL; /* hush the compiler */
2237 }
2238 case FOREIGN_bool:
2239 # ifdef SCHEME_BIG_ENDIAN
2240 if (sizeof(int)<sizeof(intptr_t) && ret_loc) {
2241 ((int*)W_OFFSET(dst,delta))[0] = 0;
2242 delta += (sizeof(intptr_t)-sizeof(int));
2243 }
2244 # endif /* SCHEME_BIG_ENDIAN */
2245 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2246 if (sizeof(int)<sizeof(intptr_t) && ret_loc) {
2247 ((int*)W_OFFSET(dst,delta))[0] = 0;
2248 }
2249 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2250
2251 if (1) {
2252 int tmp;
2253 tmp = MZ_TYPE_CAST(int, SCHEME_TRUEP(val));
2254 (((int*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2255 } else {
2256 return wrong_value(who, "_bool", val);;
2257 return NULL; /* hush the compiler */
2258 }
2259 case FOREIGN_stdbool:
2260 # ifdef SCHEME_BIG_ENDIAN
2261 if (sizeof(stdbool)<sizeof(intptr_t) && ret_loc) {
2262 ((int*)W_OFFSET(dst,delta))[0] = 0;
2263 delta += (sizeof(intptr_t)-sizeof(stdbool));
2264 }
2265 # endif /* SCHEME_BIG_ENDIAN */
2266 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2267 if (sizeof(stdbool)<sizeof(intptr_t) && ret_loc) {
2268 ((int*)W_OFFSET(dst,delta))[0] = 0;
2269 }
2270 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2271
2272 if (1) {
2273 stdbool tmp;
2274 tmp = MZ_TYPE_CAST(stdbool, SCHEME_TRUEP(val));
2275 (((stdbool*)W_OFFSET(dst,delta))[0]) = tmp; return NULL;
2276 } else {
2277 return wrong_value(who, "_stdbool", val);;
2278 return NULL; /* hush the compiler */
2279 }
2280 case FOREIGN_string_ucs_4:
2281 # ifdef SCHEME_BIG_ENDIAN
2282 if (sizeof(mzchar*)<sizeof(intptr_t) && ret_loc) {
2283 ((int*)W_OFFSET(dst,delta))[0] = 0;
2284 delta += (sizeof(intptr_t)-sizeof(mzchar*));
2285 }
2286 # endif /* SCHEME_BIG_ENDIAN */
2287 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2288 if (sizeof(mzchar*)<sizeof(intptr_t) && ret_loc) {
2289 ((int*)W_OFFSET(dst,delta))[0] = 0;
2290 }
2291 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2292
2293 if (SCHEME_FALSEP_OR_CHAR_STRINGP(val)) {
2294 mzchar* tmp;
2295 tmp = MZ_TYPE_CAST(mzchar*, ucs4_string_or_null_to_ucs4_pointer(val));
2296 if (basetype_p == NULL || tmp == NULL || 0) {
2297 (((mzchar**)W_OFFSET(dst,delta))[0]) = tmp;
2298 return NULL;
2299 } else {
2300 *basetype_p = FOREIGN_string_ucs_4;
2301 return tmp;
2302 }
2303 } else {
2304 return wrong_value(who, "_string/ucs-4", val);;
2305 return NULL; /* hush the compiler */
2306 }
2307 case FOREIGN_string_utf_16:
2308 # ifdef SCHEME_BIG_ENDIAN
2309 if (sizeof(unsigned short*)<sizeof(intptr_t) && ret_loc) {
2310 ((int*)W_OFFSET(dst,delta))[0] = 0;
2311 delta += (sizeof(intptr_t)-sizeof(unsigned short*));
2312 }
2313 # endif /* SCHEME_BIG_ENDIAN */
2314 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2315 if (sizeof(unsigned short*)<sizeof(intptr_t) && ret_loc) {
2316 ((int*)W_OFFSET(dst,delta))[0] = 0;
2317 }
2318 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2319
2320 if (SCHEME_FALSEP_OR_CHAR_STRINGP(val)) {
2321 unsigned short* tmp;
2322 tmp = MZ_TYPE_CAST(unsigned short*, ucs4_string_or_null_to_utf16_pointer(val));
2323 if (basetype_p == NULL || tmp == NULL || 0) {
2324 (((unsigned short**)W_OFFSET(dst,delta))[0]) = tmp;
2325 return NULL;
2326 } else {
2327 *basetype_p = FOREIGN_string_utf_16;
2328 return tmp;
2329 }
2330 } else {
2331 return wrong_value(who, "_string/utf-16", val);;
2332 return NULL; /* hush the compiler */
2333 }
2334 case FOREIGN_bytes:
2335 # ifdef SCHEME_BIG_ENDIAN
2336 if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2337 ((int*)W_OFFSET(dst,delta))[0] = 0;
2338 delta += (sizeof(intptr_t)-sizeof(char*));
2339 }
2340 # endif /* SCHEME_BIG_ENDIAN */
2341 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2342 if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2343 ((int*)W_OFFSET(dst,delta))[0] = 0;
2344 }
2345 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2346
2347 if (SCHEME_FALSEP(val)||SCHEME_BYTE_STRINGP(val)) {
2348 char* tmp;
2349 tmp = MZ_TYPE_CAST(char*, SCHEME_FALSEP(val)?NULL:SCHEME_BYTE_STR_VAL(val));
2350 if (basetype_p == NULL || tmp == NULL || 0) {
2351 (((char**)W_OFFSET(dst,delta))[0]) = tmp;
2352 return NULL;
2353 } else {
2354 *basetype_p = FOREIGN_bytes;
2355 return tmp;
2356 }
2357 } else {
2358 return wrong_value(who, "_bytes", val);;
2359 return NULL; /* hush the compiler */
2360 }
2361 case FOREIGN_path:
2362 # ifdef SCHEME_BIG_ENDIAN
2363 if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2364 ((int*)W_OFFSET(dst,delta))[0] = 0;
2365 delta += (sizeof(intptr_t)-sizeof(char*));
2366 }
2367 # endif /* SCHEME_BIG_ENDIAN */
2368 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2369 if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2370 ((int*)W_OFFSET(dst,delta))[0] = 0;
2371 }
2372 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2373
2374 if (SCHEME_FALSEP(val)||SCHEME_PATH_STRINGP(val)) {
2375 char* tmp;
2376 tmp = MZ_TYPE_CAST(char*, SCHEME_FALSEP(val)?NULL:SCHEME_PATH_VAL(TO_PATH(val)));
2377 if (basetype_p == NULL || tmp == NULL || 0) {
2378 (((char**)W_OFFSET(dst,delta))[0]) = tmp;
2379 return NULL;
2380 } else {
2381 *basetype_p = FOREIGN_path;
2382 return tmp;
2383 }
2384 } else {
2385 return wrong_value(who, "_path", val);;
2386 return NULL; /* hush the compiler */
2387 }
2388 case FOREIGN_symbol:
2389 # ifdef SCHEME_BIG_ENDIAN
2390 if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2391 ((int*)W_OFFSET(dst,delta))[0] = 0;
2392 delta += (sizeof(intptr_t)-sizeof(char*));
2393 }
2394 # endif /* SCHEME_BIG_ENDIAN */
2395 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2396 if (sizeof(char*)<sizeof(intptr_t) && ret_loc) {
2397 ((int*)W_OFFSET(dst,delta))[0] = 0;
2398 }
2399 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2400
2401 if (SCHEME_SYMBOLP(val)) {
2402 char* tmp;
2403 tmp = MZ_TYPE_CAST(char*, SCHEME_SYM_VAL(val));
2404 if (basetype_p == NULL || tmp == NULL || !is_gcable_pointer(val)) {
2405 (((char**)W_OFFSET(dst,delta))[0]) = tmp;
2406 return NULL;
2407 } else {
2408 *basetype_p = FOREIGN_symbol;
2409 return tmp;
2410 }
2411 } else {
2412 return wrong_value(who, "_symbol", val);;
2413 return NULL; /* hush the compiler */
2414 }
2415 case FOREIGN_pointer:
2416 # ifdef SCHEME_BIG_ENDIAN
2417 if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2418 ((int*)W_OFFSET(dst,delta))[0] = 0;
2419 delta += (sizeof(intptr_t)-sizeof(void*));
2420 }
2421 # endif /* SCHEME_BIG_ENDIAN */
2422 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2423 if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2424 ((int*)W_OFFSET(dst,delta))[0] = 0;
2425 }
2426 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2427 val = unwrap_cpointer_property(val);
2428 if (SCHEME_FFIANYPTRP(val)) {
2429 void* tmp; intptr_t toff;
2430 tmp = MZ_TYPE_CAST(void*, SCHEME_FFIANYPTR_VAL(val));
2431 toff = SCHEME_FFIANYPTR_OFFSET(val);
2432 if (basetype_p == NULL || (tmp == NULL && toff == 0) || !is_gcable_pointer(val)) {
2433 if (_offset) *_offset = 0;
2434 (((void**)W_OFFSET(dst,delta))[0]) = (void*)W_OFFSET(tmp, toff);;
2435 return NULL;
2436 } else {
2437 *basetype_p = FOREIGN_pointer;
2438 toff = SCHEME_FFIANYPTR_OFFSET(val);
2439 if (_offset) *_offset = toff;
2440 return _offset ? tmp : (void*)W_OFFSET(tmp, toff);
2441 }
2442 } else {
2443 return wrong_value(who, "_pointer", val);;
2444 return NULL; /* hush the compiler */
2445 }
2446 case FOREIGN_gcpointer:
2447 # ifdef SCHEME_BIG_ENDIAN
2448 if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2449 ((int*)W_OFFSET(dst,delta))[0] = 0;
2450 delta += (sizeof(intptr_t)-sizeof(void*));
2451 }
2452 # endif /* SCHEME_BIG_ENDIAN */
2453 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2454 if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2455 ((int*)W_OFFSET(dst,delta))[0] = 0;
2456 }
2457 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2458 val = unwrap_cpointer_property(val);
2459 if (SCHEME_FFIANYPTRP(val)) {
2460 void* tmp; intptr_t toff;
2461 tmp = MZ_TYPE_CAST(void*, SCHEME_FFIANYPTR_VAL(val));
2462 toff = SCHEME_FFIANYPTR_OFFSET(val);
2463 if (basetype_p == NULL || (tmp == NULL && toff == 0) || 0) {
2464 if (_offset) *_offset = 0;
2465 (((void**)W_OFFSET(dst,delta))[0]) = (void*)W_OFFSET(tmp, toff);;
2466 return NULL;
2467 } else {
2468 *basetype_p = FOREIGN_gcpointer;
2469 toff = SCHEME_FFIANYPTR_OFFSET(val);
2470 if (_offset) *_offset = toff;
2471 return _offset ? tmp : (void*)W_OFFSET(tmp, toff);
2472 }
2473 } else {
2474 return wrong_value(who, "_gcpointer", val);;
2475 return NULL; /* hush the compiler */
2476 }
2477 case FOREIGN_scheme:
2478 # ifdef SCHEME_BIG_ENDIAN
2479 if (sizeof(Scheme_Object*)<sizeof(intptr_t) && ret_loc) {
2480 ((int*)W_OFFSET(dst,delta))[0] = 0;
2481 delta += (sizeof(intptr_t)-sizeof(Scheme_Object*));
2482 }
2483 # endif /* SCHEME_BIG_ENDIAN */
2484 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2485 if (sizeof(Scheme_Object*)<sizeof(intptr_t) && ret_loc) {
2486 ((int*)W_OFFSET(dst,delta))[0] = 0;
2487 }
2488 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2489
2490 if (1) {
2491 Scheme_Object* tmp;
2492 tmp = MZ_TYPE_CAST(Scheme_Object*, val);
2493 if (basetype_p == NULL || tmp == NULL || 0) {
2494 (((Scheme_Object**)W_OFFSET(dst,delta))[0]) = tmp;
2495 return NULL;
2496 } else {
2497 *basetype_p = FOREIGN_scheme;
2498 return tmp;
2499 }
2500 } else {
2501 return wrong_value(who, "_scheme", val);;
2502 return NULL; /* hush the compiler */
2503 }
2504 case FOREIGN_fpointer:
2505 # ifdef SCHEME_BIG_ENDIAN
2506 if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2507 ((int*)W_OFFSET(dst,delta))[0] = 0;
2508 delta += (sizeof(intptr_t)-sizeof(void*));
2509 }
2510 # endif /* SCHEME_BIG_ENDIAN */
2511 # ifdef FFI_CALLBACK_NEED_INT_CLEAR
2512 if (sizeof(void*)<sizeof(intptr_t) && ret_loc) {
2513 ((int*)W_OFFSET(dst,delta))[0] = 0;
2514 }
2515 # endif /* FFI_CALLBACK_NEED_INT_CLEAR */
2516 if (!(ret_loc)) return wrong_value(who, "_fpointer", val);;
2517 break;
2518 case FOREIGN_struct:
2519 case FOREIGN_array:
2520 case FOREIGN_union:
2521 val = unwrap_cpointer_property(val);
2522 if (!SCHEME_FFIANYPTRP(val)) {
2523 switch (CTYPE_PRIMLABEL(type)) {
2524 case FOREIGN_struct:
2525 return wrong_value(who, "(_struct ....)", val);
2526 break;
2527 case FOREIGN_array:
2528 return wrong_value(who, "(_array ....)", val);
2529 break;
2530 default:
2531 case FOREIGN_union:
2532 return wrong_value(who, "(_union ....)", val);
2533 break;
2534 }
2535 }
2536 {
2537 void* p = SCHEME_FFIANYPTR_VAL(val);
2538 intptr_t poff = SCHEME_FFIANYPTR_OFFSET(val);
2539 if (basetype_p == NULL) {
2540 if (p == NULL && poff == 0)
2541 scheme_signal_error("FFI pointer value was NULL");
2542 memcpy(W_OFFSET(dst, delta), W_OFFSET(p, poff),
2543 CTYPE_PRIMTYPE(type)->size);
2544 return NULL;
2545 } else {
2546 *basetype_p = CTYPE_PRIMLABEL(type);
2547 if (_offset && is_gcable_pointer(val)) {
2548 *_offset = poff;
2549 return p;
2550 } else {
2551 return W_OFFSET(p, poff);
2552 }
2553 }
2554 }
2555 default: scheme_signal_error("corrupt foreign type: %V", type);
2556 }
2557 return NULL; /* hush the compiler */
2558 }
2559 #undef SET_CTYPE
2560
2561 /*****************************************************************************/
2562 /* C type information */
2563
2564 /* (ctype-sizeof type) -> int, returns 0 for void, error if not a C type */
2565 #define MYNAME "ctype-sizeof"
foreign_ctype_sizeof(int argc,Scheme_Object * argv[])2566 static Scheme_Object *foreign_ctype_sizeof(int argc, Scheme_Object *argv[])
2567 {
2568 intptr_t size;
2569 size = ctype_sizeof(argv[0]);
2570 if (size >= 0) return scheme_make_integer(size);
2571 else scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
2572 return NULL; /* hush the compiler */
2573 }
2574 #undef MYNAME
2575
2576 /* (ctype-alignof type) -> int, returns 0 for void, error if not a C type */
2577 #define MYNAME "ctype-alignof"
foreign_ctype_alignof(int argc,Scheme_Object * argv[])2578 static Scheme_Object *foreign_ctype_alignof(int argc, Scheme_Object *argv[])
2579 {
2580 Scheme_Object *type;
2581 type = get_ctype_base(argv[0]);
2582 if (type == NULL) scheme_wrong_contract(MYNAME, "ctype?", 0, argc, argv);
2583 else return scheme_make_integer(CTYPE_PRIMTYPE(type)->alignment);
2584 return NULL; /* hush the compiler */
2585 }
2586 #undef MYNAME
2587
2588 /* (compiler-sizeof symbols) -> int, where symbols name some C type.
2589 * The symbols are in 'int 'char 'void 'short 'long '*, order does not matter,
2590 * when a single symbol is used, a list is not needed.
2591 * (This is about actual C types, not C type objects.) */
2592 #define MYNAME "compiler-sizeof"
foreign_compiler_sizeof(int argc,Scheme_Object * argv[])2593 static Scheme_Object *foreign_compiler_sizeof(int argc, Scheme_Object *argv[])
2594 {
2595 int res=0;
2596 int basetype = 0; /* 1=int, 2=char, 3=void, 4=float, 5=double, 6=wchar_t */
2597 int intsize = 0; /* "short" => decrement, "long" => increment */
2598 int stars = 0; /* number of "*"s */
2599 int must_list = 0;
2600 Scheme_Object *l = argv[0], *p;
2601 while (!SAME_OBJ(l, scheme_null)) {
2602 if (SCHEME_PAIRP(l)) { p = SCHEME_CAR(l); l = SCHEME_CDR(l); must_list = 1;}
2603 else if (must_list) { p = scheme_false; l = scheme_null; }
2604 else { p = l; l = scheme_null; }
2605 if (!SCHEME_SYMBOLP(p)) {
2606 scheme_wrong_contract(MYNAME, "(or/c symbol? (listof symbol?))", 0, argc, argv);
2607 } else if (!strcmp(SCHEME_SYM_VAL(p),"int")) {
2608 if (basetype==0) basetype=1;
2609 else scheme_signal_error(MYNAME": extraneous type: %V", p);
2610 } else if (!strcmp(SCHEME_SYM_VAL(p),"char")) {
2611 if (basetype==0) basetype=2;
2612 else scheme_signal_error(MYNAME": extraneous type: %V", p);
2613 } else if (!strcmp(SCHEME_SYM_VAL(p),"wchar")) {
2614 if (basetype==0) basetype=6;
2615 else scheme_signal_error(MYNAME": extraneous type: %V", p);
2616 } else if (!strcmp(SCHEME_SYM_VAL(p),"void")) {
2617 if (basetype==0) basetype=3;
2618 else scheme_signal_error(MYNAME": extraneous type: %V", p);
2619 } else if (!strcmp(SCHEME_SYM_VAL(p),"float")) {
2620 if (basetype==0) basetype=4;
2621 else scheme_signal_error(MYNAME": extraneous type: %V", p);
2622 } else if (!strcmp(SCHEME_SYM_VAL(p),"double")) {
2623 if (basetype==0 || basetype==4) basetype=5;
2624 else scheme_signal_error(MYNAME": extraneous type: %V", p);
2625 } else if (!strcmp(SCHEME_SYM_VAL(p),"short")) {
2626 if (intsize>0)
2627 scheme_signal_error(MYNAME": cannot use both 'short and 'long");
2628 else intsize--;
2629 } else if (!strcmp(SCHEME_SYM_VAL(p),"long")) {
2630 if (intsize<0)
2631 scheme_signal_error(MYNAME": cannot use both 'short and 'long");
2632 else intsize++;
2633 } else if (!strcmp(SCHEME_SYM_VAL(p),"*")) {
2634 stars++;
2635 } else {
2636 scheme_wrong_contract(MYNAME, "(or/c ctype-symbol? (listof ctype-symbol?))", 0, argc, argv);
2637 }
2638 }
2639 if (stars > 1)
2640 scheme_signal_error(MYNAME": cannot handle more than one '*");
2641 if (intsize < -1)
2642 scheme_signal_error(MYNAME": cannot handle more than one 'short");
2643 if (intsize > 2)
2644 scheme_signal_error(MYNAME": cannot handle more than two 'long");
2645 if (basetype == 0) basetype = 1; /* int is the default type */
2646 /* don't assume anything, so it can be used to verify compiler assumptions */
2647 /* (only forbid stuff that the compiler doesn't allow) */
2648 # define RETSIZE(t) res=((stars==0)?sizeof(t):sizeof(t *))
2649 switch (basetype) {
2650 case 1: /* int */
2651 switch (intsize) {
2652 case 0: RETSIZE(int); break;
2653 case 1: RETSIZE(long int); break;
2654 # ifdef INT64_AS_LONG_LONG
2655 case 2: RETSIZE(_int64); break; /* MSVC doesn't allow long long */
2656 # else /* INT64_AS_LONG_LONG undefined */
2657 case 2: RETSIZE(long long int); break;
2658 # endif /* INT64_AS_LONG_LONG */
2659 case -1: RETSIZE(short int); break;
2660 }
2661 break;
2662 case 2: /* char */
2663 if (intsize==0) RETSIZE(char);
2664 else scheme_signal_error(MYNAME": cannot qualify 'char");
2665 break;
2666 case 3: /* void */
2667 if (intsize==0 && stars>0) RETSIZE(int); /* avoid sizeof(void) */
2668 else if (stars==0)
2669 scheme_signal_error(MYNAME": cannot use 'void without a '*");
2670 else scheme_signal_error(MYNAME": cannot qualify 'void");
2671 break;
2672 case 4: /* float */
2673 if (intsize==0) RETSIZE(float);
2674 else scheme_signal_error(MYNAME": bad qualifiers for 'float");
2675 break;
2676 case 5: /* double */
2677 if (intsize==0) RETSIZE(double);
2678 else if (intsize==1) RETSIZE(mz_long_double);
2679 else scheme_signal_error(MYNAME": bad qualifiers for 'double");
2680 break;
2681 case 6: /* wchar_t */
2682 if (intsize==0) RETSIZE(wchar_t);
2683 else scheme_signal_error(MYNAME": cannot qualify 'wchar");
2684 break;
2685 default:
2686 scheme_signal_error(MYNAME": internal error (unexpected type %d)",
2687 basetype);
2688 }
2689 # undef RETSIZE
2690 return scheme_make_integer(res);
2691 }
2692 #undef MYNAME
2693
2694 /*****************************************************************************/
2695 /* Pointer type user functions */
2696
mode_to_allocator(const char * who,Scheme_Object * mode)2697 static Scheme_Malloc_Proc mode_to_allocator(const char *who, Scheme_Object *mode)
2698 {
2699 Scheme_Malloc_Proc mf;
2700
2701 if (SAME_OBJ(mode, nonatomic_sym)) mf = scheme_malloc;
2702 else if (SAME_OBJ(mode, atomic_sym)) mf = scheme_malloc_atomic;
2703 else if (SAME_OBJ(mode, stubborn_sym)) mf = scheme_malloc_stubborn;
2704 else if (SAME_OBJ(mode, eternal_sym)) mf = scheme_malloc_eternal;
2705 else if (SAME_OBJ(mode, uncollectable_sym)) mf = scheme_malloc_uncollectable;
2706 else if (SAME_OBJ(mode, interior_sym)) mf = scheme_malloc_allow_interior;
2707 else if (SAME_OBJ(mode, atomic_interior_sym)) mf = scheme_malloc_atomic_allow_interior;
2708 else if (SAME_OBJ(mode, raw_sym)) mf = malloc;
2709 else if (SAME_OBJ(mode, tagged_sym)) mf = scheme_malloc_tagged;
2710 else {
2711 scheme_signal_error("%s: bad allocation mode: %V", who, mode);
2712 return NULL; /* hush the compiler */
2713 }
2714
2715 return mf;
2716 }
2717
ctype_allocator(Scheme_Object * type)2718 static Scheme_Malloc_Proc ctype_allocator(Scheme_Object *type)
2719 {
2720 Scheme_Object *mode;
2721
2722 mode = CTYPE_BASETYPE(type);
2723 if (!SCHEME_PAIRP(mode))
2724 mode = atomic_sym;
2725 else {
2726 mode = SCHEME_CAR(mode);
2727 if (!SCHEME_SYMBOLP(mode))
2728 mode = atomic_sym;
2729 }
2730
2731 return mode_to_allocator("_struct", mode);
2732 }
2733
2734 /* (malloc num type cpointer mode) -> pointer */
2735 /* The arguments for this function are:
2736 * - num: bytes to allocate, or the number of instances of type when given,
2737 * - type: malloc the size of this type (or num instances of it),
2738 * - cpointer: a source pointer to copy contents from,
2739 * - mode: a symbol for different allocation functions to use - one of
2740 * 'nonatomic, 'atomic, 'stubborn, 'uncollectable, 'eternal, 'tagged,
2741 * or 'raw (the last one is for using the real malloc)
2742 * - if an additional 'fail-ok flag is given, then scheme_malloc_fail_ok is
2743 * used with the chosen malloc function
2744 * The arguments can be specified in any order at all since they are all
2745 * different types, the only requirement is for a size, either a number of
2746 * bytes or a type. If no mode is specified, then scheme_malloc will be used
2747 * when the type is any pointer, otherwise scheme_malloc_atomic is used. */
2748 #define MYNAME "malloc"
foreign_malloc(int argc,Scheme_Object * argv[])2749 static Scheme_Object *foreign_malloc(int argc, Scheme_Object *argv[])
2750 {
2751 int i, failok=0;
2752 intptr_t size=0, num=-1;
2753 void *from = NULL, *res = NULL;
2754 intptr_t foff = 0;
2755 Scheme_Object *mode = NULL, *a, *base = NULL;
2756 Scheme_Malloc_Proc mf;
2757 for (i=0; i<argc; i++) {
2758 a = unwrap_cpointer_property(argv[i]);
2759 if (SCHEME_INTP(a)) {
2760 if (num != -1)
2761 scheme_signal_error(MYNAME": specifying a second integer size: %V", a);
2762 num = SCHEME_INT_VAL(a);
2763 if (num < 0)
2764 scheme_wrong_contract(MYNAME, "(and/c exact-nonnegative-integer? fixnum?)", 0, argc, argv);
2765 } else if (SCHEME_CTYPEP(a)) {
2766 if (size != 0)
2767 scheme_signal_error(MYNAME": specifying a second type: %V", a);
2768 if (NULL == (base = get_ctype_base(a)))
2769 scheme_wrong_contract(MYNAME, "ctype?", i, argc, argv);
2770 size = ctype_sizeof(a);
2771 if (size <= 0)
2772 wrong_void(MYNAME, NULL, 0, i, argc, argv);
2773 } else if (SAME_OBJ(a, fail_ok_sym)) {
2774 failok = 1;
2775 } else if (SCHEME_SYMBOLP(a)) {
2776 if (mode != NULL)
2777 scheme_signal_error(MYNAME": specifying a second mode symbol: %V", a);
2778 mode = a;
2779 } else if (SCHEME_FFIANYPTRP(a) && !SCHEME_FALSEP(a)) {
2780 if (from != NULL)
2781 scheme_signal_error(MYNAME": specifying a second source pointer: %V",
2782 a);
2783 from = SCHEME_FFIANYPTR_VAL(a);
2784 foff = SCHEME_FFIANYPTR_OFFSET(a);
2785 } else {
2786 scheme_wrong_contract(MYNAME,
2787 "(or/c (and/c exact-nonnegative-integer? fixnum?)\n"
2788 " ctype?\n"
2789 " (or/c 'nonatomic 'stubborn 'uncollectable\n"
2790 " 'eternal 'interior 'atomic-interior\n"
2791 " 'tagged 'raw)\n"
2792 " 'fail-on\n"
2793 " (and/c cpointer? (not/c #f)))",
2794 i, argc, argv);
2795 }
2796 }
2797 if (!num) return scheme_false;
2798 if ((num == -1) && (size == 0)) scheme_signal_error(MYNAME": no size given");
2799 size = mult_check_overflow(MYNAME, ((size==0) ? 1 : size), ((num==-1) ? 1 : num));
2800 if (mode == NULL)
2801 mf = (base != NULL && CTYPE_PRIMTYPE(base) == &ffi_type_gcpointer)
2802 ? scheme_malloc : scheme_malloc_atomic;
2803 else
2804 mf = mode_to_allocator(MYNAME, mode);
2805 res = scheme_malloc_fail_ok(mf,size);
2806 if (failok && (res == NULL)) scheme_signal_error("malloc: out of memory");
2807
2808 /* We might want to use foff as the object base address if from is NULL,
2809 * therefore set a src point to use in memcpy to clarify this */
2810 {
2811 void *src = NULL;
2812 if (from != NULL)
2813 src = W_OFFSET(from, foff);
2814 else if (foff != 0)
2815 src = (void *)foff;
2816 if (src != NULL && res != NULL)
2817 memcpy(res, src, size);
2818 }
2819
2820 if (SAME_OBJ(mode, raw_sym))
2821 return scheme_make_foreign_external_cpointer(res);
2822 else
2823 return scheme_make_foreign_cpointer(res);
2824 }
2825 #undef MYNAME
2826
2827 #define NON_NULL_CPOINTER "(and/c cpointer? (not/c (lambda (p) (pointer-equal? p #f))))"
2828
2829 /* (end-stubborn-change ptr) */
2830 #define MYNAME "end-stubborn-change"
foreign_end_stubborn_change(int argc,Scheme_Object * argv[])2831 static Scheme_Object *foreign_end_stubborn_change(int argc, Scheme_Object *argv[])
2832 {
2833 void *ptr;
2834 intptr_t poff;
2835 Scheme_Object *cp;
2836 cp = unwrap_cpointer_property(argv[0]);
2837 if (!SCHEME_FFIANYPTRP(cp))
2838 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2839 ptr = SCHEME_FFIANYPTR_VAL(cp);
2840 poff = SCHEME_FFIANYPTR_OFFSET(cp);
2841 if ((ptr == NULL) && (poff == 0))
2842 scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
2843 scheme_end_stubborn_change(W_OFFSET(ptr, poff));
2844 return scheme_void;
2845 }
2846 #undef MYNAME
2847
2848 /* (free ptr) */
2849 /* This is useful for raw-malloced objects, including objects from C libraries
2850 * that the library is mallocing itself. */
2851 #define MYNAME "free"
foreign_free(int argc,Scheme_Object * argv[])2852 static Scheme_Object *foreign_free(int argc, Scheme_Object *argv[])
2853 {
2854 void *ptr;
2855 intptr_t poff;
2856 Scheme_Object *cp;
2857 cp = unwrap_cpointer_property(argv[0]);
2858 if (!SCHEME_FFIANYPTRP(cp))
2859 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2860 ptr = SCHEME_FFIANYPTR_VAL(cp);
2861 poff = SCHEME_FFIANYPTR_OFFSET(cp);
2862 if ((ptr == NULL) && (poff == 0))
2863 scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
2864 free(W_OFFSET(ptr, poff));
2865 return scheme_void;
2866 }
2867 #undef MYNAME
2868
2869 /* (malloc-immobile-cell v) */
2870 #define MYNAME "malloc-immobile-cell"
foreign_malloc_immobile_cell(int argc,Scheme_Object * argv[])2871 static Scheme_Object *foreign_malloc_immobile_cell(int argc, Scheme_Object *argv[])
2872 {
2873 void *p;
2874 p = scheme_malloc_immobile_box(argv[0]);
2875 return scheme_make_foreign_external_cpointer(p); /* <- beware: macro duplicates `p' */
2876 }
2877 #undef MYNAME
2878
2879 /* (free-immobile-cell b) */
2880 #define MYNAME "free-immobile-cell"
foreign_free_immobile_cell(int argc,Scheme_Object * argv[])2881 static Scheme_Object *foreign_free_immobile_cell(int argc, Scheme_Object *argv[])
2882 {
2883 void *ptr;
2884 intptr_t poff;
2885 Scheme_Object *cp;
2886 cp = unwrap_cpointer_property(argv[0]);
2887 if (!SCHEME_FFIANYPTRP(cp))
2888 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2889 ptr = SCHEME_FFIANYPTR_VAL(cp);
2890 poff = SCHEME_FFIANYPTR_OFFSET(cp);
2891 if ((ptr == NULL) && (poff == 0))
2892 scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
2893 scheme_free_immobile_box((void **)W_OFFSET(ptr, poff));
2894 return scheme_void;
2895 }
2896 #undef MYNAME
2897
2898 /* (ptr-add cptr offset-k [type])
2899 * Adds an offset to a pointer, returning an offset_cpointer value
2900 * (ptr-add! cptr offset-k [type])
2901 * Modifies an existing offset_cpointer value by adjusting its offset field,
2902 * returns void
2903 */
do_ptr_add(const char * who,int is_bang,int argc,Scheme_Object ** argv)2904 static Scheme_Object *do_ptr_add(const char *who, int is_bang,
2905 int argc, Scheme_Object **argv)
2906 {
2907 intptr_t noff;
2908 Scheme_Object *cp;
2909 cp = unwrap_cpointer_property(argv[0]);
2910 if (is_bang) {
2911 if (!SCHEME_CPOINTER_W_OFFSET_P(cp))
2912 scheme_wrong_contract(who, "offset-ptr?", 0, argc, argv);
2913 } else {
2914 if (!SCHEME_FFIANYPTRP(cp))
2915 scheme_wrong_contract(who, "cpointer?", 0, argc, argv);
2916 }
2917 if (!scheme_get_int_val(argv[1], &noff))
2918 wrong_intptr(who, 1, argc, argv);
2919 if (argc > 2) {
2920 if (SCHEME_CTYPEP(argv[2])) {
2921 intptr_t size;
2922 size = ctype_sizeof(argv[2]);
2923 if (size < 0)
2924 scheme_wrong_contract(who, "ctype?", 2, argc, argv);
2925 if (size <= 0) wrong_void(who, NULL, 0, 2, argc, argv);
2926 noff = mult_check_overflow(who, noff, size);
2927 } else
2928 scheme_wrong_contract(who, "ctype?", 2, argc, argv);
2929 }
2930 if (is_bang) {
2931 intptr_t delta;
2932 delta = add_check_overflow(who, ((Scheme_Offset_Cptr*)(cp))->offset, noff);
2933 ((Scheme_Offset_Cptr*)(cp))->offset = delta;
2934 return scheme_void;
2935 } else {
2936 intptr_t delta;
2937 delta = add_check_overflow(who, SCHEME_FFIANYPTR_OFFSET(cp), noff);
2938 if (SCHEME_CPTRP(cp) && (SCHEME_CPTR_FLAGS(cp) & 0x1))
2939 return scheme_make_offset_external_cptr
2940 (SCHEME_FFIANYPTR_VAL(cp),
2941 delta,
2942 (SCHEME_CPTRP(cp)) ? SCHEME_CPTR_TYPE(cp) : NULL);
2943 else
2944 return scheme_make_offset_cptr
2945 (SCHEME_FFIANYPTR_VAL(cp),
2946 delta,
2947 (SCHEME_CPTRP(cp)) ? SCHEME_CPTR_TYPE(cp) : NULL);
2948 }
2949 }
2950
2951 /* (ptr-add cptr offset-k [type]) */
2952 #define MYNAME "ptr-add"
foreign_ptr_add(int argc,Scheme_Object * argv[])2953 static Scheme_Object *foreign_ptr_add(int argc, Scheme_Object *argv[])
2954 {
2955 return do_ptr_add(MYNAME, 0, argc, argv);
2956 }
2957 #undef MYNAME
2958 /* (ptr-add! cptr offset-k [type]) */
2959 #define MYNAME "ptr-add!"
foreign_ptr_add_bang(int argc,Scheme_Object * argv[])2960 static Scheme_Object *foreign_ptr_add_bang(int argc, Scheme_Object *argv[])
2961 {
2962 return do_ptr_add(MYNAME, 1, argc, argv);
2963 }
2964 #undef MYNAME
2965
2966 /* (offset-ptr? x) */
2967 /* Returns #t if the argument is a cpointer with an offset */
2968 #define MYNAME "offset-ptr?"
foreign_offset_ptr_p(int argc,Scheme_Object * argv[])2969 static Scheme_Object *foreign_offset_ptr_p(int argc, Scheme_Object *argv[])
2970 {
2971 Scheme_Object *cp;
2972 cp = unwrap_cpointer_property(argv[0]);
2973 return (SCHEME_CPOINTER_W_OFFSET_P(cp)) ? scheme_true : scheme_false;
2974 }
2975 #undef MYNAME
2976
2977 /* (ptr-offset ptr) */
2978 /* Returns the offset of a cpointer (0 if it's not an offset pointer) */
2979 #define MYNAME "ptr-offset"
foreign_ptr_offset(int argc,Scheme_Object * argv[])2980 static Scheme_Object *foreign_ptr_offset(int argc, Scheme_Object *argv[])
2981 {
2982 Scheme_Object *cp;
2983 cp = unwrap_cpointer_property(argv[0]);
2984 if (!SCHEME_FFIANYPTRP(cp))
2985 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
2986 return scheme_make_integer_value(SCHEME_FFIANYPTR_OFFSET(cp));
2987 }
2988 #undef MYNAME
2989
2990 /* (set-ptr-offset! ptr offset [type]) */
2991 /* Sets the offset of an offset-cpointer (possibly multiplied by the size of
2992 * the given ctype) */
2993 #define MYNAME "set-ptr-offset!"
foreign_set_ptr_offset_bang(int argc,Scheme_Object * argv[])2994 static Scheme_Object *foreign_set_ptr_offset_bang(int argc, Scheme_Object *argv[])
2995 {
2996 intptr_t noff;
2997 Scheme_Object *cp;
2998 cp = unwrap_cpointer_property(argv[0]);
2999 if (!SCHEME_CPOINTER_W_OFFSET_P(cp))
3000 scheme_wrong_contract(MYNAME, "offset-ptr?", 0, argc, argv);
3001 if (!scheme_get_int_val(argv[1], &noff))
3002 wrong_intptr(MYNAME, 1, argc, argv);
3003 if (argc > 2) {
3004 if (SCHEME_CTYPEP(argv[2])) {
3005 intptr_t size;
3006 if (NULL == get_ctype_base(argv[2]))
3007 scheme_wrong_contract(MYNAME, "ctype?", 2, argc, argv);
3008 size = ctype_sizeof(argv[2]);
3009 if (size <= 0)
3010 wrong_void(MYNAME, NULL, 0, 2, argc, argv);
3011 noff = mult_check_overflow(MYNAME, noff, size);
3012 } else
3013 scheme_wrong_contract(MYNAME, "ctype?", 2, argc, argv);
3014 }
3015 ((Scheme_Offset_Cptr*)(cp))->offset = noff;
3016 return scheme_void;
3017 }
3018 #undef MYNAME
3019
3020 /* (mem{move,cpy} dest-ptr [dest-offset] src-ptr [src-offset] count [ctype])
3021 * Copies count * sizeof(ctype) bytes
3022 * from src-ptr + src-offset * sizeof(ctype)
3023 * to dest-ptr + dest-offset * sizeof(ctype).
3024 * --or--
3025 * (memset dest-ptr [dest-offset] byte count [ctype])
3026 * Sets count * sizeof(ctype) bytes to byte
3027 * at dest-ptr + dest-offset * sizeof(ctype) */
do_memop(const char * who,int mode,int argc,Scheme_Object ** argv)3028 static Scheme_Object *do_memop(const char *who, int mode,
3029 int argc, Scheme_Object **argv)
3030 /* mode 0=>memset, 1=>memmove, 2=>memcpy */
3031 {
3032 void *src = NULL, *dest = NULL;
3033 intptr_t soff = 0, doff = 0, count, v, mult = 0;
3034 int i, j, ch = 0, argc1 = argc;
3035 Scheme_Object *cp;
3036
3037 /* arg parsing: last optional ctype, then count, then fill byte for memset,
3038 * then the first and second pointer+offset pair. */
3039
3040 /* get the optional last ctype multiplier */
3041 if (SCHEME_CTYPEP(argv[argc1-1])) {
3042 argc1--;
3043 mult = ctype_sizeof(argv[argc1]);
3044 if (mult < 0)
3045 scheme_wrong_contract(who, "ctype?", argc1, argc, argv);
3046 if (mult <= 0)
3047 wrong_void(who, NULL, 0, argc1, argc, argv);
3048 }
3049
3050 /* get the count argument */
3051 argc1--;
3052 if ((!scheme_get_int_val(argv[argc1], &count)) || (count < 0))
3053 wrong_intptr(who, argc1, argc, argv);
3054 if (mult) count *= mult;
3055
3056 /* get the fill byte for memset */
3057 if (!mode) {
3058 argc1--;
3059 ch = SCHEME_INTP(argv[argc1]) ? SCHEME_INT_VAL(argv[argc1]) : -1;
3060 if ((ch < 0) || (ch > 255))
3061 scheme_wrong_contract(who, "byte?", argc1, argc, argv);
3062 }
3063
3064 /* get the two pointers + offsets */
3065 i = 0;
3066 for (j=0; j<2; j++) {
3067 if (!mode && j==1) break; /* memset needs only a dest argument */
3068 if (!(i<argc1))
3069 scheme_raise_exn(MZEXN_FAIL_CONTRACT,
3070 "%s: missing a pointer argument for %s",
3071 who, (j == 0 ? "destination" : "source"));
3072 cp = unwrap_cpointer_property(argv[i]);
3073 if (!SCHEME_FFIANYPTRP(cp))
3074 scheme_wrong_contract(who, "cpointer?", i, argc, argv);
3075 switch (j) {
3076 case 0: dest = SCHEME_FFIANYPTR_VAL(cp);
3077 doff = SCHEME_FFIANYPTR_OFFSET(cp);
3078 break;
3079 case 1: src = SCHEME_FFIANYPTR_VAL(cp);
3080 soff = SCHEME_FFIANYPTR_OFFSET(cp);
3081 break;
3082 }
3083 i++;
3084 if ((i<argc1) && SCHEME_EXACT_INTEGERP(argv[i])) {
3085 if (!scheme_get_int_val(argv[i], &v))
3086 wrong_intptr(who, i, argc, argv);
3087 if (mult) v *= mult;
3088 switch (j) {
3089 case 0: doff += v; break;
3090 case 1: soff += v; break;
3091 }
3092 i++;
3093 }
3094 }
3095
3096 /* verify that there are no unused leftovers */
3097 if (!(i==argc1))
3098 scheme_arg_mismatch(who, "unexpected extra argument: ", argv[i]);
3099
3100 switch (mode) {
3101 case 0: memset (W_OFFSET(dest, doff), ch, count); break;
3102 case 1: memmove(W_OFFSET(dest, doff), W_OFFSET(src, soff), count); break;
3103 case 2: memcpy (W_OFFSET(dest, doff), W_OFFSET(src, soff), count); break;
3104 }
3105
3106 return scheme_void;
3107 }
3108
3109 #define MYNAME "vector->cpointer"
foreign_vector_to_cpointer(int argc,Scheme_Object * argv[])3110 static Scheme_Object *foreign_vector_to_cpointer(int argc, Scheme_Object *argv[])
3111 {
3112 if (!SCHEME_VECTORP(argv[0]))
3113 scheme_wrong_contract(MYNAME, "vector?", 0, argc, argv);
3114 return scheme_make_offset_cptr(argv[0], (intptr_t)SCHEME_VEC_ELS((Scheme_Object *)0x0), NULL);
3115 }
3116 #undef MYNAME
3117
3118 #define MYNAME "flvector->cpointer"
foreign_flvector_to_cpointer(int argc,Scheme_Object * argv[])3119 static Scheme_Object *foreign_flvector_to_cpointer(int argc, Scheme_Object *argv[])
3120 {
3121 if (!SCHEME_FLVECTORP(argv[0]))
3122 scheme_wrong_contract(MYNAME, "flvector?", 0, argc, argv);
3123 return scheme_make_offset_cptr(argv[0], (intptr_t)SCHEME_FLVEC_ELS((Scheme_Object *)0x0), NULL);
3124 }
3125 #undef MYNAME
3126
3127 #define MYNAME "extflvector->cpointer"
foreign_extflvector_to_cpointer(int argc,Scheme_Object * argv[])3128 static Scheme_Object *foreign_extflvector_to_cpointer(int argc, Scheme_Object *argv[])
3129 {
3130 # ifdef MZ_LONG_DOUBLE
3131 if (!SCHEME_EXTFLVECTORP(argv[0]))
3132 scheme_wrong_contract(MYNAME, "extflvector?", 0, argc, argv);
3133 return scheme_make_offset_cptr(argv[0], (intptr_t)SCHEME_EXTFLVEC_ELS((Scheme_Object *)0x0), NULL);
3134 # else /* MZ_LONG_DOUBLE undefined */
3135 scheme_raise_exn(MZEXN_FAIL_UNSUPPORTED,
3136 MYNAME ": " NOT_SUPPORTED_STR);
3137 return NULL;
3138 # endif /* MZ_LONG_DOUBLE */
3139 }
3140 #undef MYNAME
3141
3142 #define MYNAME "memset"
foreign_memset(int argc,Scheme_Object * argv[])3143 static Scheme_Object *foreign_memset(int argc, Scheme_Object *argv[])
3144 {
3145 return do_memop(MYNAME, 0, argc, argv);
3146 }
3147 #undef MYNAME
3148 #define MYNAME "memmove"
foreign_memmove(int argc,Scheme_Object * argv[])3149 static Scheme_Object *foreign_memmove(int argc, Scheme_Object *argv[])
3150 {
3151 return do_memop(MYNAME, 1, argc, argv);
3152 }
3153 #undef MYNAME
3154 #define MYNAME "memcpy"
foreign_memcpy(int argc,Scheme_Object * argv[])3155 static Scheme_Object *foreign_memcpy(int argc, Scheme_Object *argv[])
3156 {
3157 return do_memop(MYNAME, 2, argc, argv);
3158 }
3159 #undef MYNAME
3160
3161 static Scheme_Object *abs_sym;
3162
3163 /* (ptr-ref cpointer type [['abs] n]) -> the object at the given location */
3164 /* n defaults to 0 which is the only value that should be used with ffi_objs */
3165 /* if n is given, an 'abs flag can precede it to make n be a byte offset */
3166 /* rather than some multiple of sizeof(type). */
3167 /* WARNING: there are *NO* checks at all, this is raw C level code. */
3168 #define MYNAME "ptr-ref"
foreign_ptr_ref(int argc,Scheme_Object * argv[])3169 static Scheme_Object *foreign_ptr_ref(int argc, Scheme_Object *argv[])
3170 {
3171 intptr_t size=0; void *ptr; Scheme_Object *base;
3172 intptr_t delta; int gcsrc=1;
3173 Scheme_Object *cp, *already_ptr = NULL;
3174 cp = unwrap_cpointer_property(argv[0]);
3175 if (!SCHEME_FFIANYPTRP(cp))
3176 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3177 ptr = SCHEME_FFIANYPTR_VAL(cp);
3178 delta = SCHEME_FFIANYPTR_OFFSET(cp);
3179 if (!is_gcable_pointer(cp))
3180 gcsrc = 0;
3181 if ((ptr == NULL) && (delta == 0))
3182 scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
3183 if (NULL == (base = get_ctype_base(argv[1])))
3184 scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3185 size = ctype_sizeof(base);
3186
3187 if (CTYPE_PRIMLABEL(base) == FOREIGN_fpointer) {
3188 if (SCHEME_FFIOBJP(cp)) {
3189 /* The ffiobj pointer is the function pointer. */
3190 ptr = cp;
3191 delta = (intptr_t)&(((ffi_obj_struct*)0x0)->obj);
3192 /* Helps propagate a function name from `ffi-obj' to `ffi-call': */
3193 already_ptr = cp;
3194 }
3195 }
3196
3197 if (size < 0) {
3198 /* should not happen */
3199 scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3200 } else if (size == 0) {
3201 wrong_void(MYNAME, NULL, 0, 1, argc, argv);
3202 }
3203
3204 if (argc > 3) {
3205 if (!SAME_OBJ(argv[2],abs_sym))
3206 scheme_wrong_contract(MYNAME, "'abs", 2, argc, argv);
3207 if (!SCHEME_INTP(argv[3]))
3208 scheme_wrong_contract(MYNAME, "fixnum?", 3, argc, argv);
3209 if (SCHEME_INT_VAL(argv[3])) {
3210 delta = add_check_overflow(MYNAME, delta, SCHEME_INT_VAL(argv[3]));
3211 already_ptr = NULL;
3212 }
3213 } else if (argc > 2) {
3214 if (!SCHEME_INTP(argv[2]))
3215 scheme_wrong_contract(MYNAME, "fixnum?", 2, argc, argv);
3216 if (!size)
3217 scheme_signal_error(MYNAME": cannot multiply fpointer type by offset");
3218 if (SCHEME_INT_VAL(argv[2])) {
3219 delta = add_check_overflow(MYNAME, delta, mult_check_overflow(MYNAME, size, SCHEME_INT_VAL(argv[2])));
3220 already_ptr = NULL;
3221 }
3222 }
3223 return C2SCHEME(already_ptr, argv[1], ptr, delta, 0, gcsrc);
3224 }
3225 #undef MYNAME
3226
scheme_foreign_ptr_ref(int argc,Scheme_Object ** argv)3227 Scheme_Object *scheme_foreign_ptr_ref(int argc, Scheme_Object **argv)
3228 {
3229 return foreign_ptr_ref(argc, argv);
3230 }
3231
3232 /* (ptr-set! cpointer type [['abs] n] value) -> void */
3233 /* n defaults to 0 which is the only value that should be used with ffi_objs */
3234 /* if n is given, an 'abs flag can precede it to make n be a byte offset */
3235 /* rather than some multiple of sizeof(type). */
3236 /* WARNING: there are *NO* checks at all, this is raw C level code. */
3237 #define MYNAME "ptr-set!"
foreign_ptr_set_bang(int argc,Scheme_Object * argv[])3238 static Scheme_Object *foreign_ptr_set_bang(int argc, Scheme_Object *argv[])
3239 {
3240 intptr_t size=0; void *ptr;
3241 intptr_t delta;
3242 Scheme_Object *val = argv[argc-1], *base;
3243 Scheme_Object *cp;
3244 cp = unwrap_cpointer_property(argv[0]);
3245 if (!SCHEME_FFIANYPTRP(cp))
3246 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3247 ptr = SCHEME_FFIANYPTR_VAL(cp);
3248 delta = SCHEME_FFIANYPTR_OFFSET(cp);
3249 if ((ptr == NULL) && (delta == 0))
3250 scheme_wrong_contract(MYNAME, NON_NULL_CPOINTER, 0, argc, argv);
3251 if (NULL == (base = get_ctype_base(argv[1])))
3252 scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3253 size = ctype_sizeof(base);
3254
3255 if (size < 0) {
3256 /* should not happen */
3257 scheme_wrong_contract(MYNAME, "ctype?", 1, argc, argv);
3258 } else if (size == 0) {
3259 wrong_void(MYNAME, NULL, 0, 1, argc, argv);
3260 }
3261
3262 if (argc > 4) {
3263 if (!SAME_OBJ(argv[2],abs_sym))
3264 scheme_wrong_contract(MYNAME, "'abs", 2, argc, argv);
3265 if (!SCHEME_INTP(argv[3]))
3266 scheme_wrong_contract(MYNAME, "fixnum?", 3, argc, argv);
3267 delta = add_check_overflow(MYNAME, delta, SCHEME_INT_VAL(argv[3]));
3268 } else if (argc > 3) {
3269 if (!SCHEME_INTP(argv[2]))
3270 scheme_wrong_contract(MYNAME, "fixnum?", 2, argc, argv);
3271 if (!size)
3272 scheme_signal_error(MYNAME": cannot multiply fpointer type by offset");
3273 delta = add_check_overflow(MYNAME, delta, mult_check_overflow(MYNAME, size, SCHEME_INT_VAL(argv[2])));
3274 }
3275 SCHEME2C(MYNAME, argv[1], ptr, delta, val, NULL, NULL, 0);
3276 return scheme_void;
3277 }
3278 #undef MYNAME
3279
scheme_foreign_ptr_set(int argc,Scheme_Object ** argv)3280 void scheme_foreign_ptr_set(int argc, Scheme_Object **argv)
3281 {
3282 (void)foreign_ptr_set_bang(argc, argv);
3283 }
3284
3285 /* (ptr-equal? cpointer cpointer) -> boolean */
3286 #define MYNAME "ptr-equal?"
foreign_ptr_equal_p(int argc,Scheme_Object * argv[])3287 static Scheme_Object *foreign_ptr_equal_p(int argc, Scheme_Object *argv[])
3288 {
3289 Scheme_Object *cp1, *cp2;
3290 cp1 = unwrap_cpointer_property(argv[0]);
3291 cp2 = unwrap_cpointer_property(argv[1]);
3292 if (!SCHEME_FFIANYPTRP(cp1))
3293 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3294 if (!SCHEME_FFIANYPTRP(cp2))
3295 scheme_wrong_contract(MYNAME, "cpointer?", 1, argc, argv);
3296 return (SAME_OBJ(cp1, cp2) ||
3297 (SCHEME_FFIANYPTR_OFFSETVAL(cp1)
3298 == SCHEME_FFIANYPTR_OFFSETVAL(cp2)))
3299 ? scheme_true : scheme_false;
3300 }
3301 #undef MYNAME
3302
3303 /* (make-sized-byte-string cpointer len) */
3304 #define MYNAME "make-sized-byte-string"
foreign_make_sized_byte_string(int argc,Scheme_Object * argv[])3305 static Scheme_Object *foreign_make_sized_byte_string(int argc, Scheme_Object *argv[])
3306 {
3307 /* Warning: no copying is done so it is possible to share string contents. */
3308 /* Warning: if source ptr has a offset, resulting string object uses shifted
3309 * pointer.
3310 * (Should use real byte-strings with new version.) */
3311 intptr_t len;
3312 Scheme_Object *cp;
3313 cp = unwrap_cpointer_property(argv[0]);
3314 if (!SCHEME_FFIANYPTRP(cp))
3315 scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv);
3316 if (!scheme_get_int_val(argv[1],&len))
3317 wrong_intptr(MYNAME, 1, argc, argv);
3318 return scheme_make_sized_byte_string(SCHEME_FFIANYPTR_OFFSETVAL(cp),
3319 len, 0);
3320 }
3321 #undef MYNAME
3322
3323 /*****************************************************************************/
3324 /* FFI named locks */
3325
3326 THREAD_LOCAL_DECL(static Scheme_Hash_Table *ffi_lock_ht);
3327
3328 #if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
make_vector_in_master(int count,Scheme_Object * val)3329 static Scheme_Object *make_vector_in_master(int count, Scheme_Object *val) {
3330 Scheme_Object *vec;
3331 void *original_gc;
3332 original_gc = GC_switch_to_master_gc();
3333 vec = scheme_make_vector(count, val);
3334 GC_switch_back_from_master(original_gc);
3335 return vec;
3336 }
3337
malloc_immobile_box_in_master(Scheme_Object * v)3338 static void **malloc_immobile_box_in_master(Scheme_Object *v)
3339 {
3340 void **imm;
3341 void *original_gc;
3342 original_gc = GC_switch_to_master_gc();
3343 imm = scheme_malloc_immobile_box(v);
3344 GC_switch_back_from_master(original_gc);
3345 return imm;
3346 }
3347 #endif
3348
name_to_ffi_lock(Scheme_Object * bstr)3349 static void *name_to_ffi_lock(Scheme_Object *bstr)
3350 {
3351 Scheme_Object *lock;
3352
3353 if (!ffi_lock_ht) {
3354 REGISTER_SO(ffi_lock_ht);
3355 ffi_lock_ht = scheme_make_hash_table_equal();
3356 }
3357
3358 lock = scheme_hash_get(ffi_lock_ht, bstr);
3359 if (!lock) {
3360 # ifdef MZ_USE_PLACES
3361 /* implement the lock with a compare-and-swap with fallback (on
3362 contention) to a place channel; this strategy has minimal
3363 overhead when there's no contention, which is good for avoiding
3364 a penalty in the common case of a single place (but it's probably
3365 not the best strategy for a contended lock) */
3366 void *lock_box, *old_lock_box;
3367
3368 lock_box = scheme_register_process_global(SCHEME_BYTE_STR_VAL(bstr), NULL);
3369 if (!lock_box) {
3370 lock = scheme_place_make_async_channel();
3371 lock = make_vector_in_master(2, lock);
3372 SCHEME_VEC_ELS(lock)[1] = scheme_make_integer(-1);
3373 lock_box = malloc_immobile_box_in_master(lock);
3374 old_lock_box = scheme_register_process_global(SCHEME_BYTE_STR_VAL(bstr), lock_box);
3375 if (old_lock_box) {
3376 scheme_free_immobile_box(lock_box);
3377 lock_box = old_lock_box;
3378 }
3379 }
3380 lock = *(Scheme_Object **)lock_box;
3381 # else /* MZ_USE_PLACES undefined */
3382 lock = scheme_make_sema(1);
3383 # endif /* MZ_USE_PLACES */
3384 scheme_hash_set(ffi_lock_ht, bstr, lock);
3385 }
3386
3387 return lock;
3388 }
3389
wait_ffi_lock(Scheme_Object * lock)3390 static void wait_ffi_lock(Scheme_Object *lock)
3391 {
3392 # ifdef MZ_USE_PLACES
3393 while (1) {
3394 if (mzrt_cas((uintptr_t*)&(SCHEME_VEC_ELS(lock)[1]),
3395 (uintptr_t)scheme_make_integer(-1),
3396 (uintptr_t)scheme_make_integer(scheme_current_place_id))) {
3397 /* obtained lock the fast way */
3398 break;
3399 } else if (!scheme_place_can_receive()) {
3400 /* We can get here while trying to terminate a place and run
3401 custodian callbacks or other shutdown actions, and since
3402 the place is shutting down, we can't commuincate with other
3403 places; since we can't pause nicely, just spin */
3404 } else {
3405 Scheme_Object *owner, *new_val;
3406 owner = SCHEME_VEC_ELS(lock)[1];
3407 if (SCHEME_INT_VAL(owner) != -1) {
3408 if (SCHEME_INT_VAL(owner) < -1) {
3409 /* other processes waiting, and now there's one more: */
3410 new_val = scheme_make_integer(SCHEME_INT_VAL(owner)-1);
3411 } else {
3412 /* notify owner that another process is now waiting: */
3413 new_val = scheme_make_integer(-2);
3414 }
3415 if (mzrt_cas((uintptr_t*)&(SCHEME_VEC_ELS(lock)[1]),
3416 (uintptr_t)owner,
3417 (uintptr_t)new_val)) {
3418 /* wait for lock the slow way - without blocking other Racket threads */
3419 (void)scheme_place_async_channel_receive(SCHEME_VEC_ELS(lock)[0]);
3420
3421 /* not waiting anymore: */
3422 while (1) {
3423 owner = SCHEME_VEC_ELS(lock)[1];
3424 if (SCHEME_INT_VAL(owner) == -2) {
3425 /* no other processes waiting */
3426 new_val = scheme_make_integer(scheme_current_place_id);
3427 } else {
3428 /* one less process waiting */
3429 new_val = scheme_make_integer(SCHEME_INT_VAL(owner)+1);
3430 }
3431 if (mzrt_cas((uintptr_t*)&(SCHEME_VEC_ELS(lock)[1]),
3432 (uintptr_t)owner,
3433 (uintptr_t)new_val)) {
3434 break;
3435 }
3436 }
3437 break;
3438 }
3439 }
3440 }
3441 }
3442 # else /* MZ_USE_PLACES undefined */
3443 scheme_wait_sema(lock, 0);
3444 # endif /* MZ_USE_PLACES */
3445 }
3446
release_ffi_lock(void * lock)3447 static void release_ffi_lock(void *lock)
3448 {
3449 # ifdef MZ_USE_PLACES
3450 if (mzrt_cas((uintptr_t *)&(SCHEME_VEC_ELS(lock)[1]),
3451 (uintptr_t)scheme_make_integer(scheme_current_place_id),
3452 (uintptr_t)scheme_make_integer(-1))) {
3453 /* released lock with no other process waiting */
3454 } else {
3455 /* assert: SCHEME_VEC_ELS(lock)[1] holds a negative
3456 number corresponding to the number of waiting processes */
3457 scheme_place_async_channel_send(SCHEME_VEC_ELS(lock)[0], scheme_false);
3458 }
3459 # else /* MZ_USE_PLACES undefined */
3460 scheme_post_sema(lock);
3461 # endif /* MZ_USE_PLACES */
3462 }
3463
3464 /*****************************************************************************/
3465
extract_varargs_after(const char * who,int argc,Scheme_Object ** argv,int argpos,int nargs)3466 static int extract_varargs_after(const char *who, int argc, Scheme_Object **argv, int argpos, int nargs)
3467 {
3468 int varargs_after;
3469
3470 if (SCHEME_FALSEP(argv[argpos]))
3471 varargs_after = -1;
3472 else if (SCHEME_INTP(argv[argpos])
3473 && (SCHEME_INT_VAL(argv[argpos]) > 0)) {
3474 varargs_after = SCHEME_INT_VAL(argv[argpos]);
3475 } else if (SCHEME_BIGNUMP(argv[argpos])
3476 && SCHEME_BIGPOS((argv[argpos]))) {
3477 varargs_after = nargs + 1;
3478 } else {
3479 varargs_after = -1;
3480 scheme_wrong_contract(who, "(or/c exact-positive-integer? #f)", argpos, argc, argv);
3481 }
3482 if (varargs_after > nargs)
3483 scheme_contract_error(who, "varargs-after value is too large",
3484 "given value", 1, argv[argpos],
3485 "argument count", 1, scheme_make_integer(nargs),
3486 NULL);
3487
3488 return varargs_after;
3489 }
3490
3491 /*****************************************************************************/
3492 /* Calling foreign function objects */
3493
3494 #define MAX_QUICK_ARGS 16
3495
3496 typedef void(*VoidFun)(void);
3497
3498 #ifdef MZ_USE_PLACES
3499
3500 typedef struct FFI_Orig_Place_Call {
3501 int needs_queue;
3502 ffi_cif *cif;
3503 void *c_func;
3504 intptr_t cfoff;
3505 int nargs;
3506 ForeignAny *ivals;
3507 void **avalues;
3508 intptr_t *offsets;
3509 void *p;
3510 void **signal_handle;
3511 struct FFI_Orig_Place_Call *next, *prev;
3512 } FFI_Orig_Place_Call;
3513
3514 static mzrt_mutex *orig_place_mutex;
3515 static FFI_Orig_Place_Call *orig_place_calls, *orig_place_calls_tail;
3516 static void *orig_place_signal_handle;
3517
3518 static void check_foreign_work(int check_for_in_original);
3519
ffi_call_in_orig_place(ffi_cif * cif,void * c_func,intptr_t cfoff,int nargs,GC_CAN_IGNORE ForeignAny * ivals,void ** avalues,intptr_t * offsets,void * p)3520 static void ffi_call_in_orig_place(ffi_cif *cif, void *c_func, intptr_t cfoff,
3521 int nargs, GC_CAN_IGNORE ForeignAny *ivals, void **avalues,
3522 intptr_t *offsets, void *p)
3523 /* This function can trigger a GC, but it won't escape --- unless
3524 the called function goes back to Racket and raises an exception,
3525 and raising an exception in a callback creates all sorts of
3526 other problems, anyway. No other Racket threads will run in the
3527 place, so it's ok for the arguments to have stack addresses. */
3528 {
3529 FFI_Orig_Place_Call *todo;
3530 void *sh;
3531 int ready;
3532
3533 if (cached_orig_place_todo) {
3534 todo = cached_orig_place_todo;
3535 cached_orig_place_todo = NULL;
3536 } else
3537 todo = (FFI_Orig_Place_Call *)malloc(sizeof(FFI_Orig_Place_Call));
3538 sh = scheme_get_signal_handle();
3539 todo->signal_handle = sh;
3540 todo->needs_queue = 1;
3541
3542 /* It would be simplest to just block the current place while the
3543 original place handles the call. Unfortunately, something like a
3544 master GC might be required between now and when the call is
3545 handled. So, we have to block in an atomic-like way to minimize
3546 GCs while we wait, but still wake up on an external signal. */
3547
3548 GC_check_master_gc_request();
3549 /* If a GC is needed from here on, a signal will be posted
3550 to the current place */
3551
3552 while (1) {
3553 todo->cif = cif;
3554 todo->c_func = c_func;
3555 todo->cfoff = cfoff;
3556 todo->nargs = nargs;
3557 todo->ivals = ivals;
3558 todo->avalues = avalues;
3559 todo->offsets = offsets;
3560 todo->p = p;
3561
3562 mzrt_mutex_lock(orig_place_mutex);
3563 if (todo->needs_queue) {
3564 todo->next = orig_place_calls;
3565 todo->prev = NULL;
3566 if (orig_place_calls)
3567 orig_place_calls->prev = todo;
3568 else
3569 orig_place_calls_tail = todo;
3570 orig_place_calls = todo;
3571 ready = 0;
3572 } else {
3573 ready = !todo->signal_handle;
3574 }
3575 mzrt_mutex_unlock(orig_place_mutex);
3576
3577 if (!ready) {
3578 /* Tell original-place thread that there's work: */
3579 scheme_signal_received_at(orig_place_signal_handle);
3580 /* Wait for notificiation or a master-GC request: */
3581 scheme_wait_until_signal_received();
3582 }
3583
3584 mzrt_mutex_lock(orig_place_mutex);
3585 if (!todo->signal_handle) {
3586 /* Done */
3587 mzrt_mutex_unlock(orig_place_mutex);
3588 if (!cached_orig_place_todo)
3589 cached_orig_place_todo = todo;
3590 else
3591 free(todo);
3592 break;
3593 } else {
3594 /* Pause to allow actions such as a master GC.... */
3595 if (todo->needs_queue) {
3596 /* Remove from queue while we might GC: */
3597 if (todo->prev)
3598 todo->prev->next = todo->next;
3599 else
3600 orig_place_calls = todo->next;
3601 if (todo->next)
3602 todo->next->prev = todo->prev;
3603 else
3604 orig_place_calls_tail = todo->prev;
3605 } else {
3606 /* The call is being handled, so it's too late
3607 to remove it from the queue! */
3608 }
3609 mzrt_mutex_unlock(orig_place_mutex);
3610
3611 /* Here's the atomic pause: */
3612 GC_check_master_gc_request();
3613 scheme_start_atomic();
3614 scheme_thread_block(0.0);
3615 scheme_end_atomic_no_swap();
3616
3617 /* Since we called scheme_thread_block() in atomic mode,
3618 it doesn't check for foreign callbacks. We'd like
3619 to handle those anyway, since the call in the original
3620 place may lead to a callback that should run in
3621 this place. */
3622 # ifndef MZ_USE_FFIPOLL
3623 check_foreign_work(0);
3624 # endif /* MZ_USE_FFIPOLL */
3625 }
3626 }
3627 }
3628 #endif
3629
finish_ffi_call(ffi_cif * cif,void * c_func,intptr_t cfoff,int nargs,GC_CAN_IGNORE ForeignAny * ivals,void ** avalues,intptr_t * offsets,void * p)3630 static void finish_ffi_call(ffi_cif *cif, void *c_func, intptr_t cfoff,
3631 int nargs, GC_CAN_IGNORE ForeignAny *ivals, void **avalues,
3632 intptr_t *offsets, void *p)
3633 /* Complete an FFI call in non-GC mode, so that arguments won't move around: */
3634 XFORM_SKIP_PROC
3635 {
3636 int i;
3637 for (i=0; i<nargs; i++) {
3638 if ((avalues[i] == NULL) && !offsets[i]) /* if this was a non-pointer... */
3639 avalues[i] = &(ivals[i]); /* ... set the avalues pointer */
3640 else if ((ivals[i].x_fixnum != FOREIGN_struct)
3641 && (ivals[i].x_fixnum != FOREIGN_union)) { /* if *not* a struct... */
3642 /* ... set the ivals pointer (pointer type doesn't matter) and avalues */
3643 ivals[i].x_pointer = avalues[i];
3644 avalues[i] = &(ivals[i]);
3645 } else if (offsets[i]) {
3646 /* struct argument has an offset */
3647 avalues[i] = (char *)avalues[i] + offsets[i];
3648 }
3649 /* Otherwise it was a struct pointer, and avalues[i] is already fine. */
3650 /* Add offset, if any: */
3651 if (offsets[i] != 0) {
3652 ivals[i].x_pointer = (char *)ivals[i].x_pointer + offsets[i];
3653 }
3654 }
3655 /* Finally, call the function */
3656 ffi_call(cif, (VoidFun)W_OFFSET(c_func, cfoff), p, avalues);
3657 }
3658
finish_ffi_call_handle_exn(ffi_cif * cif,void * c_func,intptr_t cfoff,int nargs,GC_CAN_IGNORE ForeignAny * ivals,void ** avalues,intptr_t * offsets,void * p,Scheme_Object * lock)3659 static void finish_ffi_call_handle_exn(ffi_cif *cif, void *c_func, intptr_t cfoff,
3660 int nargs, GC_CAN_IGNORE ForeignAny *ivals, void **avalues,
3661 intptr_t *offsets, void *p,
3662 Scheme_Object *lock)
3663 {
3664 mz_jmp_buf * volatile save, fresh;
3665
3666 save = scheme_current_thread->error_buf;
3667 scheme_current_thread->error_buf = &fresh;
3668
3669 if (scheme_setjmp(scheme_error_buf)) {
3670 if (SCHEME_TRUEP(lock))
3671 release_ffi_lock(lock);
3672 scheme_end_in_scheduler();
3673 scheme_longjmp(*save, 1);
3674 } else {
3675 finish_ffi_call(cif, c_func, cfoff,
3676 nargs, ivals, avalues,
3677 offsets, p);
3678 }
3679
3680 scheme_current_thread->error_buf = save;
3681 }
3682
ffi_do_call(int argc,Scheme_Object * argv[],Scheme_Object * self)3683 static Scheme_Object *ffi_do_call(int argc, Scheme_Object *argv[], Scheme_Object *self)
3684 /* data := {name, c-function, itypes, otype, cif} */
3685 {
3686 Scheme_Object *data = SCHEME_PRIM_CLOSURE_ELS(self)[0];
3687 int curried = !SCHEME_VEC_ELS(data)[1] && !SCHEME_INT_VAL(SCHEME_VEC_ELS(data)[5]);
3688 const char *name = ((Scheme_Primitive_Closure *)self)->p.name;
3689 void *c_func = (curried
3690 ? (void*)SCHEME_PRIM_CLOSURE_ELS(self)[1]
3691 : (void*)(SCHEME_VEC_ELS(data)[1]));
3692 Scheme_Object *itypes = SCHEME_VEC_ELS(data)[2];
3693 Scheme_Object *otype = SCHEME_VEC_ELS(data)[3];
3694 Scheme_Object *base;
3695 ffi_cif *cif = (ffi_cif*)(SCHEME_VEC_ELS(data)[4]);
3696 intptr_t cfoff = (curried
3697 ? SCHEME_INT_VAL(SCHEME_PRIM_CLOSURE_ELS(self)[2])
3698 : SCHEME_INT_VAL(SCHEME_VEC_ELS(data)[5]));
3699 int save_errno = SCHEME_INT_VAL(SCHEME_VEC_ELS(data)[6]);
3700 Scheme_Object *lock = SCHEME_VEC_ELS(data)[7];
3701 int callback_exns = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[8]);
3702 #ifdef MZ_USE_PLACES
3703 int orig_place = SCHEME_TRUEP(SCHEME_VEC_ELS(data)[9]);
3704 #endif
3705 int nargs /* = cif->nargs, after checking cif */;
3706 /* When the foreign function is called, we need an array (ivals) of nargs
3707 * ForeignAny objects to store the actual C values that are created, and we
3708 * need another array (avalues) for the pointers to these values (this is
3709 * what libffi actually uses). To make things more fun, ForeignAny is
3710 * problematic for the precise GC, since it is sometimes a pointer and
3711 * sometime not. To deal with this, while converting argv objects into
3712 * ivals, scheme_to_c will save pointer values in avalues, so the GC can,
3713 * ignore ivals -- just before we reach the actual call, avalues is
3714 * overwritten, but from that point on it is all C code so there is no
3715 * problem. Hopefully.
3716 * (Things get complicated if the C call can involve GC (usually due to a
3717 * Racket callback), but then the programmer need to arrange for pointers
3718 * that cannot move. Because of all this, the *only* array that should not
3719 * be ignored by the GC is avalues.)
3720 */
3721 ForeignAny *ivals;
3722 void **avalues, *p, *newp;
3723 GC_CAN_IGNORE ForeignAny stack_ivals[MAX_QUICK_ARGS], oval;
3724 void *stack_avalues[MAX_QUICK_ARGS];
3725 intptr_t stack_offsets[MAX_QUICK_ARGS];
3726 int i;
3727 intptr_t basetype, offset, *offsets;
3728 #ifdef MZ_USE_PLACES
3729 if (orig_place && (scheme_current_place_id == 0) && !MZ_USE_FFIPOLL_COND)
3730 orig_place = 0;
3731 #endif
3732 if (!cif) {
3733 scheme_signal_error("ffi-call: foreign-function reference was already finalized%s%s",
3734 name ? "\n name: " : "",
3735 name ? name : "");
3736 return NULL;
3737 }
3738 nargs = cif->nargs;
3739 if ((nargs <= MAX_QUICK_ARGS)) {
3740 ivals = stack_ivals;
3741 avalues = stack_avalues;
3742 offsets = stack_offsets;
3743 } else {
3744 ivals = scheme_malloc_atomic_allow_interior(nargs * sizeof(ForeignAny));
3745 avalues = scheme_malloc(nargs * sizeof(void*));
3746 offsets = scheme_malloc_atomic(nargs * sizeof(intptr_t));
3747 }
3748 /* iterate on input values and types */
3749 for (i=0; i<nargs; i++, itypes=SCHEME_CDR(itypes)) {
3750 /* convert argv[i] according to current itype */
3751 offset = 0;
3752 p = SCHEME2C(name, SCHEME_CAR(itypes), &(ivals[i]), 0, argv[i], &basetype,
3753 &offset, 0);
3754 if ((p != NULL) || offset) {
3755 avalues[i] = p;
3756 ivals[i].x_fixnum = basetype; /* remember the base type */
3757 } else {
3758 avalues[i] = NULL;
3759 }
3760 offsets[i] = offset;
3761 }
3762 base = get_ctype_base(otype); /* verified below, so cannot be NULL */
3763 /* If this is a struct return value, then need to malloc in any case, even if
3764 * the size is smaller than ForeignAny, because this value will be
3765 * returned. */
3766 if ((CTYPE_PRIMLABEL(base) == FOREIGN_struct)
3767 || (CTYPE_PRIMLABEL(base) == FOREIGN_union)) {
3768 /* need to have p be a pointer that is invisible to the GC */
3769 p = malloc(CTYPE_PRIMTYPE(base)->size);
3770 {
3771 Scheme_Malloc_Proc mf;
3772 mf = ctype_allocator(base);
3773 newp = mf(CTYPE_PRIMTYPE(base)->size);
3774 }
3775 } else {
3776 p = &oval;
3777 newp = NULL;
3778 }
3779
3780 if (SCHEME_TRUEP(lock))
3781 wait_ffi_lock(lock);
3782
3783 #ifdef MZ_USE_PLACES
3784 if (orig_place)
3785 ffi_call_in_orig_place(cif, c_func, cfoff,
3786 nargs, ivals, avalues,
3787 offsets, p);
3788 else
3789 #endif
3790 {
3791 if (callback_exns)
3792 finish_ffi_call_handle_exn(cif, c_func, cfoff,
3793 nargs, ivals, avalues,
3794 offsets, p, lock);
3795 else
3796 finish_ffi_call(cif, c_func, cfoff,
3797 nargs, ivals, avalues,
3798 offsets, p);
3799 }
3800
3801 if (SCHEME_TRUEP(lock))
3802 release_ffi_lock(lock);
3803
3804 /* Use `data' to make sure it's kept alive (as far as the GC is concerned)
3805 until the foreign call returns: */
3806 if ((void*)data == (void*)scheme_true)
3807 scheme_signal_error("dummy test succeeded!?");
3808
3809 if (save_errno != 0) save_errno_values(save_errno);
3810 ivals = NULL; /* no need now to hold on to this */
3811 for (i=0; i<nargs; i++) { avalues[i] = NULL; } /* no need for these refs */
3812 avalues = NULL;
3813 switch (CTYPE_PRIMLABEL(base)) {
3814 case FOREIGN_struct:
3815 case FOREIGN_union:
3816 memcpy(newp, p, CTYPE_PRIMTYPE(base)->size);
3817 free(p);
3818 p = newp;
3819 break;
3820 case FOREIGN_array:
3821 /* array as result is treated as a pointer, so
3822 adjust `p' to make C2SCHEME work right */
3823 p = *(void **)p;
3824 break;
3825 }
3826 return C2SCHEME(NULL, otype, p, 0, 1, 1);
3827 }
3828
ffi_do_call_k()3829 static Scheme_Object *ffi_do_call_k()
3830 {
3831 Scheme_Thread *p = scheme_current_thread;
3832 Scheme_Object **argv, *self;
3833
3834 argv = (Scheme_Object **)p->ku.k.p1;
3835 self = (Scheme_Object *)p->ku.k.p2;
3836
3837 p->ku.k.p1 = NULL;
3838 p->ku.k.p2 = NULL;
3839
3840 return ffi_do_call(p->ku.k.i1, argv, self);
3841 }
3842
ffi_do_call_after_stack_check(int argc,Scheme_Object * argv[],Scheme_Object * self)3843 static Scheme_Object *ffi_do_call_after_stack_check(int argc, Scheme_Object *argv[], Scheme_Object *self)
3844 {
3845 /* Make sure we have an extra-comfortable amount of space on the
3846 stack before calling into foreign code: */
3847 if (!scheme_no_stack_overflow && scheme_is_stack_too_shallow()) {
3848 Scheme_Thread *p = scheme_current_thread;
3849 p->ku.k.i1 = argc;
3850 p->ku.k.p1 = argv;
3851 p->ku.k.p2 = self;
3852 return scheme_handle_stack_overflow(ffi_do_call_k);
3853 } else
3854 return ffi_do_call(argc, argv, self);
3855 }
3856
3857 /* see below */
free_fficall_data(void * data,void * p)3858 void free_fficall_data(void *data, void *p)
3859 {
3860 SCHEME_VEC_ELS(data)[4] = NULL;
3861 free(((ffi_cif*)p)->arg_types);
3862 free(p);
3863 }
3864
3865 static Scheme_Object *ffi_name = NULL;
3866
make_ffi_call_from_curried(int argc,Scheme_Object * argv[],Scheme_Object * self)3867 static Scheme_Object *make_ffi_call_from_curried(int argc, Scheme_Object *argv[], Scheme_Object *self)
3868 {
3869 Scheme_Object *data = SCHEME_PRIM_CLOSURE_ELS(self)[0];
3870 Scheme_Object *a[3], *name, *itypes, *obj, *cp;
3871 const char *name_str;
3872 intptr_t ooff;
3873 int nargs;
3874
3875 cp = unwrap_cpointer_property(argv[0]);
3876 if (!SCHEME_FFIANYPTRP(cp))
3877 scheme_wrong_contract("make-ffi-call", "(or/c ffi-obj? cpointer?)", 0, argc, argv);
3878 obj = SCHEME_FFIANYPTR_VAL(cp);
3879 ooff = SCHEME_FFIANYPTR_OFFSET(cp);
3880 if ((obj == NULL) && (ooff == 0))
3881 scheme_wrong_contract("make-ffi-call", NON_NULL_CPOINTER, 0, argc, argv);
3882
3883 name = SCHEME_VEC_ELS(data)[0];
3884 if (SCHEME_FFIOBJP(cp))
3885 name_str = ((ffi_obj_struct*)(cp))->name;
3886 else
3887 name_str = SCHEME_BYTE_STR_VAL(name);
3888
3889 itypes = SCHEME_VEC_ELS(data)[2];
3890
3891 nargs = scheme_proper_list_length(itypes);
3892
3893 a[0] = data;
3894 a[1] = obj;
3895 a[2] = scheme_make_integer_value(ooff);
3896
3897 return scheme_make_prim_closure_w_arity(ffi_do_call_after_stack_check,
3898 3, a,
3899 name_str,
3900 nargs, nargs);
3901
3902 }
3903
ffi_call_or_curry(const char * who,int curry,int argc,Scheme_Object ** argv)3904 static Scheme_Object *ffi_call_or_curry(const char *who, int curry, int argc, Scheme_Object **argv) {
3905 # define ARGPOS(n) ((n) - (curry ? 1 : 0))
3906 Scheme_Object *itypes = argv[ARGPOS(1)];
3907 Scheme_Object *otype = argv[ARGPOS(2)];
3908 Scheme_Object *obj, *data, *p, *base, *cp, *name, *a[1];
3909 ffi_abi abi;
3910 int varargs_after;
3911 intptr_t ooff;
3912 GC_CAN_IGNORE ffi_type *rtype, **atypes;
3913 GC_CAN_IGNORE ffi_cif *cif;
3914 int i, nargs, save_errno, callback_exns;
3915 Scheme_Object *lock = scheme_false;
3916 Scheme_Performance_State perf_state;
3917 # ifdef MZ_USE_PLACES
3918 int orig_place = MZ_USE_FFIPOLL_COND;
3919 # define FFI_CALL_VEC_SIZE 10
3920 # else /* MZ_USE_PLACES undefined */
3921 # define FFI_CALL_VEC_SIZE 9
3922 # endif /* MZ_USE_PLACES */
3923 scheme_performance_record_start(&perf_state);
3924 if (!curry) {
3925 cp = unwrap_cpointer_property(argv[ARGPOS(0)]);
3926 if (!SCHEME_FFIANYPTRP(cp))
3927 scheme_wrong_contract(who, "(or/c ffi-obj? cpointer?)", ARGPOS(0), argc, argv);
3928 obj = SCHEME_FFIANYPTR_VAL(cp);
3929 ooff = SCHEME_FFIANYPTR_OFFSET(cp);
3930 if ((obj == NULL) && (ooff == 0))
3931 scheme_wrong_contract(who, NON_NULL_CPOINTER, 0, argc, argv);
3932 } else {
3933 cp = NULL;
3934 obj = NULL;
3935 ooff = 0;
3936 }
3937 nargs = scheme_proper_list_length(itypes);
3938 if (nargs < 0)
3939 scheme_wrong_contract(who, "list?", ARGPOS(1), argc, argv);
3940 if (NULL == (base = get_ctype_base(otype)))
3941 scheme_wrong_contract(who, "ctype?", ARGPOS(2), argc, argv);
3942 rtype = CTYPE_ARG_PRIMTYPE(base);
3943 abi = GET_ABI(who, ARGPOS(3));
3944 if (argc > ARGPOS(4)) {
3945 save_errno = -1;
3946 if (SCHEME_FALSEP(argv[ARGPOS(4)]))
3947 save_errno = 0;
3948 else if (SCHEME_SYMBOLP(argv[ARGPOS(4)])
3949 && !SCHEME_SYM_WEIRDP(argv[ARGPOS(4)])) {
3950 if (!strcmp(SCHEME_SYM_VAL(argv[ARGPOS(4)]), "posix"))
3951 save_errno = 1;
3952 else if (!strcmp(SCHEME_SYM_VAL(argv[ARGPOS(4)]), "windows"))
3953 save_errno = 2;
3954 }
3955 if (save_errno == -1) {
3956 scheme_wrong_contract(who, "(or/c 'posix 'windows #f)", ARGPOS(4), argc, argv);
3957 }
3958 } else
3959 save_errno = 0;
3960 # if defined(MZ_USE_PLACES) && !defined(MZ_USE_FFIPOLL)
3961 if (argc > ARGPOS(5)) orig_place = SCHEME_TRUEP(argv[ARGPOS(5)]);
3962 else orig_place = 0;
3963 # endif /* defined(MZ_USE_PLACES) && !defined(MZ_USE_FFIPOLL) */
3964 if (argc > ARGPOS(6)) {
3965 if (!SCHEME_FALSEP(argv[ARGPOS(6)])) {
3966 if (!SCHEME_CHAR_STRINGP(argv[ARGPOS(6)]))
3967 scheme_wrong_contract(who, "(or/c string? #f)", ARGPOS(6), argc, argv);
3968 lock = name_to_ffi_lock(scheme_char_string_to_byte_string(argv[ARGPOS(6)]));
3969 }
3970 }
3971 /* ARGPOS(7) is `blocking?`, but we don't use that */
3972 if (argc > ARGPOS(8)) {
3973 varargs_after = extract_varargs_after(who, argc, argv, ARGPOS(8), nargs);
3974 } else
3975 varargs_after = -1;
3976 if (argc > ARGPOS(9))
3977 callback_exns = SCHEME_TRUEP(argv[ARGPOS(9)]);
3978 else
3979 callback_exns = 0;
3980
3981 if (cp && SCHEME_FFIOBJP(cp))
3982 name = scheme_make_byte_string(((ffi_obj_struct*)(cp))->name);
3983 else
3984 name = ffi_name;
3985 atypes = malloc(nargs * sizeof(ffi_type*));
3986 for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) {
3987 if (NULL == (base = get_ctype_base(SCHEME_CAR(p))))
3988 scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv);
3989 if (CTYPE_PRIMLABEL(base) == FOREIGN_void)
3990 wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv);
3991 atypes[i] = CTYPE_ARG_PRIMTYPE(base);
3992 }
3993 cif = malloc(sizeof(ffi_cif));
3994 if (varargs_after == -1) {
3995 if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
3996 scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
3997 } else {
3998 if (ffi_prep_cif_var(cif, abi, varargs_after, nargs, rtype, atypes) != FFI_OK)
3999 scheme_signal_error("internal error: ffi_prep_cif_var did not return FFI_OK");
4000 }
4001 data = scheme_make_vector(FFI_CALL_VEC_SIZE, NULL);
4002 SCHEME_VEC_ELS(data)[0] = name;
4003 SCHEME_VEC_ELS(data)[1] = obj;
4004 SCHEME_VEC_ELS(data)[2] = itypes;
4005 SCHEME_VEC_ELS(data)[3] = otype;
4006 SCHEME_VEC_ELS(data)[4] = (Scheme_Object*)cif;
4007 SCHEME_VEC_ELS(data)[5] = scheme_make_integer(ooff);
4008 SCHEME_VEC_ELS(data)[6] = scheme_make_integer(save_errno);
4009 SCHEME_VEC_ELS(data)[7] = lock;
4010 SCHEME_VEC_ELS(data)[8] = (callback_exns ? scheme_true : scheme_false);
4011 # ifdef MZ_USE_PLACES
4012 SCHEME_VEC_ELS(data)[9] = (orig_place ? scheme_true : scheme_false);
4013 # endif /* MZ_USE_PLACES */
4014 scheme_register_finalizer(data, free_fficall_data, cif, NULL, NULL);
4015 a[0] = data;
4016
4017 scheme_performance_record_end("comp-ffi-call", &perf_state);
4018
4019 if (curry) {
4020 return scheme_make_prim_closure_w_arity(make_ffi_call_from_curried,
4021 1, a,
4022 "make-ffi-call",
4023 1, 1);
4024 } else {
4025 return scheme_make_prim_closure_w_arity(ffi_do_call_after_stack_check,
4026 1, a,
4027 SCHEME_BYTE_STR_VAL(name),
4028 nargs, nargs);
4029 }
4030 #undef ARGPOS
4031 }
4032
4033 /* (ffi-call ffi-obj in-types out-type [abi save-errno? orig-place? lock-name blocking? varargs-after exns?]) -> (in-types -> out-value) */
4034 /* the real work is done by ffi_do_call above */
4035 #define MYNAME "ffi-call"
foreign_ffi_call(int argc,Scheme_Object * argv[])4036 static Scheme_Object *foreign_ffi_call(int argc, Scheme_Object *argv[])
4037 {
4038 return ffi_call_or_curry(MYNAME, 0, argc, argv);
4039 }
4040 #undef MYNAME
4041
4042 /* (ffi-call-maker in-types out-type [abi save-errno? orig-place? lock-name blocking? varargs-after exns?]) -> (ffi->obj -> (in-types -> out-value)) */
4043 /* Curried version of `ffi-call` */
4044 #define MYNAME "ffi-call-maker"
foreign_ffi_call_maker(int argc,Scheme_Object * argv[])4045 static Scheme_Object *foreign_ffi_call_maker(int argc, Scheme_Object *argv[])
4046 {
4047 return ffi_call_or_curry(MYNAME, 1, argc, argv);
4048 }
4049 #undef MYNAME
4050
4051 /*****************************************************************************/
4052 /* Racket callbacks */
4053
4054 typedef void (*ffi_callback_t)(ffi_cif* cif, void* resultp, void** args, void *userdata);
4055
extract_ffi_callback(void * userdata)4056 static ffi_callback_struct *extract_ffi_callback(void *userdata)
4057 XFORM_SKIP_PROC
4058 {
4059 ffi_callback_struct *data;
4060
4061 #ifdef MZ_PRECISE_GC
4062 {
4063 void *tmp;
4064 tmp = *((void**)userdata);
4065 data = (ffi_callback_struct *)SCHEME_WEAK_BOX_VAL(tmp);
4066 if (data == NULL) scheme_signal_error("callback lost");
4067 }
4068 #else
4069 data = (ffi_callback_struct *)userdata;
4070 #endif
4071
4072 return data;
4073 }
4074
ffi_do_callback(ffi_cif * cif,void * resultp,void ** args,void * userdata)4075 static void ffi_do_callback(ffi_cif* cif, void* resultp, void** args, void *userdata)
4076 {
4077 ffi_callback_struct *data;
4078 Scheme_Object *argv_stack[MAX_QUICK_ARGS];
4079 int argc = cif->nargs, i;
4080 Scheme_Object **argv, *p, *v, *t;
4081
4082 data = extract_ffi_callback(userdata);
4083
4084 if (argc <= MAX_QUICK_ARGS)
4085 argv = argv_stack;
4086 else
4087 argv = scheme_malloc(argc * sizeof(Scheme_Object*));
4088 if (data->sync && !SCHEME_PROCP(data->sync))
4089 scheme_start_in_scheduler();
4090 for (i=0, p=data->itypes; i<argc; i++, p=SCHEME_CDR(p)) {
4091 t = SCHEME_CAR(p);
4092 if (CTYPE_PRIMLABEL(get_ctype_base(t)) == FOREIGN_array) {
4093 /* array as argument is treated as a pointer */
4094 v = C2SCHEME(NULL, t, *(void **)(args[i]), 0, 0, 0);
4095 } else
4096 v = C2SCHEME(NULL, t, args[i], 0, 0, 0);
4097 argv[i] = v;
4098 }
4099 p = _scheme_apply(data->proc, argc, argv);
4100 SCHEME2C("callback result", data->otype, resultp, 0, p, NULL, NULL, 1);
4101 if (data->sync && !SCHEME_PROCP(data->sync))
4102 scheme_end_in_scheduler();
4103 }
4104
4105 #ifdef MZ_USE_MZRT
4106
4107 /* When OS-level thread support is available, support callbacks
4108 in foreign threads that are executed on the main Racket thread. */
4109
4110 typedef struct Queued_Callback {
4111 ffi_cif* cif;
4112 void* resultp;
4113 void** args;
4114 void *userdata;
4115 mzrt_sema *sema;
4116 int called;
4117 struct Queued_Callback *next;
4118 } Queued_Callback;
4119
4120 typedef struct FFI_Sync_Queue {
4121 Queued_Callback *callbacks; /* malloc()ed list */
4122 mzrt_mutex *lock;
4123 mzrt_os_thread_id orig_thread;
4124 void *sig_hand;
4125 } FFI_Sync_Queue;
4126
4127 THREAD_LOCAL_DECL(static struct FFI_Sync_Queue *ffi_sync_queue);
4128
callback_thunk(void * _qc,int argc,Scheme_Object * argv[])4129 static Scheme_Object *callback_thunk(void *_qc, int argc, Scheme_Object *argv[])
4130 {
4131 Queued_Callback *qc = (Queued_Callback *)_qc;
4132
4133 if (qc->called)
4134 scheme_raise_exn(MZEXN_FAIL_CONTRACT,
4135 "callback thunk for synchronization has already been called");
4136 qc->called = 1;
4137
4138 ffi_do_callback(qc->cif, qc->resultp, qc->args, qc->userdata);
4139
4140 mzrt_sema_post(qc->sema);
4141
4142 return scheme_void;
4143 }
4144
check_foreign_work(int check_for_in_original)4145 static void check_foreign_work(int check_for_in_original)
4146 # ifdef MZ_USE_FFIPOLL
4147 XFORM_SKIP_PROC
4148 # endif /* MZ_USE_FFIPOLL */
4149 {
4150 GC_CAN_IGNORE Queued_Callback *qc;
4151 ffi_callback_struct *data;
4152 Scheme_Object *a[1], *proc;
4153
4154 #ifdef MZ_USE_FFIPOLL
4155 /* We don't currently support callbacks from C to Racket in FFIPOLL
4156 mode, and this function is not allowed to touch the GC or Racket
4157 in that mode. */
4158 #else
4159 if (ffi_sync_queue) {
4160 do {
4161 mzrt_mutex_lock(ffi_sync_queue->lock);
4162 qc = ffi_sync_queue->callbacks;
4163 if (qc)
4164 ffi_sync_queue->callbacks = qc->next;
4165 mzrt_mutex_unlock(ffi_sync_queue->lock);
4166
4167 if (qc) {
4168 qc->next = NULL;
4169
4170 data = extract_ffi_callback(qc->userdata);
4171
4172 proc = scheme_make_closed_prim_w_arity(callback_thunk, (void *)qc,
4173 "callback-thunk", 0, 0);
4174 a[0] = proc;
4175
4176 proc = data->sync;
4177 if (SCHEME_BOXP(proc)) proc = SCHEME_BOX_VAL(proc);
4178
4179 scheme_start_in_scheduler();
4180 _scheme_apply(proc, 1, a);
4181 scheme_end_in_scheduler();
4182 }
4183
4184 } while (qc);
4185 }
4186 #endif
4187
4188 #ifdef MZ_USE_PLACES
4189 if (check_for_in_original && ((scheme_current_place_id == 0) || MZ_USE_FFIPOLL_COND) && orig_place_mutex) {
4190 FFI_Orig_Place_Call *todo;
4191 void *sh;
4192
4193 while (1) {
4194 mzrt_mutex_lock(orig_place_mutex);
4195 todo = orig_place_calls_tail;
4196 if (todo) {
4197 orig_place_calls_tail = todo->prev;
4198 if (todo->prev)
4199 todo->prev->next = NULL;
4200 else
4201 orig_place_calls = NULL;
4202 todo->needs_queue = 0;
4203 }
4204 mzrt_mutex_unlock(orig_place_mutex);
4205
4206 if (todo) {
4207 finish_ffi_call(todo->cif, todo->c_func, todo->cfoff,
4208 todo->nargs, todo->ivals, todo->avalues,
4209 todo->offsets, todo->p);
4210 mzrt_mutex_lock(orig_place_mutex);
4211 sh = todo->signal_handle;
4212 todo->signal_handle = NULL; /* indicates "done" */
4213 scheme_signal_received_at(sh);
4214 mzrt_mutex_unlock(orig_place_mutex);
4215 } else
4216 break;
4217 }
4218 }
4219 #endif
4220 }
4221
scheme_check_foreign_work(void)4222 void scheme_check_foreign_work(void)
4223 # ifdef MZ_USE_FFIPOLL
4224 XFORM_SKIP_PROC
4225 # endif /* MZ_USE_FFIPOLL */
4226 {
4227 check_foreign_work(1);
4228 }
4229
4230 #endif
4231
ffi_queue_callback(ffi_cif * cif,void * resultp,void ** args,void * userdata)4232 static void ffi_queue_callback(ffi_cif* cif, void* resultp, void** args, void *userdata)
4233 XFORM_SKIP_PROC
4234 {
4235 #ifdef MZ_USE_MZRT
4236 /* This function must not refer to any GCable address, not even
4237 temporarily, because a GC may occur concurrent to this
4238 function if it's in another thread. */
4239 FFI_Sync_Queue *queue;
4240 void **data = (void **)userdata;
4241
4242 queue = (FFI_Sync_Queue *)(data)[1];
4243 userdata = (data)[0];
4244
4245 if (queue->orig_thread != mz_proc_os_thread_self()) {
4246 if (data[2]) {
4247 /* constant result */
4248 memcpy(resultp, data[2], (intptr_t)data[3]);
4249 return;
4250 } else {
4251 /* queue a callback and wait: */
4252 Queued_Callback *qc;
4253 mzrt_sema *sema;
4254
4255 mzrt_sema_create(&sema, 0);
4256
4257 qc = (Queued_Callback *)malloc(sizeof(Queued_Callback));
4258 qc->cif = cif;
4259 qc->resultp = resultp;
4260 qc->args = args;
4261 qc->userdata = userdata;
4262 qc->sema = sema;
4263 qc->called = 0;
4264
4265 mzrt_mutex_lock(queue->lock);
4266 qc->next = queue->callbacks;
4267 queue->callbacks = qc;
4268 mzrt_mutex_unlock(queue->lock);
4269 scheme_signal_received_at(queue->sig_hand);
4270
4271 /* wait for the callback to be invoked in the main thread */
4272 mzrt_sema_wait(sema);
4273
4274 mzrt_sema_destroy(sema);
4275 free(qc);
4276 return;
4277 }
4278 }
4279 #endif
4280
4281 ffi_do_callback(cif, resultp, args, userdata);
4282 }
4283
4284 /* see ffi-callback below */
4285 typedef struct closure_and_cif_struct {
4286 ffi_closure closure;
4287 ffi_cif cif;
4288 #ifdef MZ_PRECISE_GC
4289 struct immobile_box *data;
4290 #else
4291 void *data;
4292 #endif
4293 } closure_and_cif;
4294
4295 /* free the above */
free_cl_cif_args(void * ignored,void * p)4296 static void free_cl_cif_args(void *ignored, void *p)
4297 {
4298 /*
4299 scheme_warning("Releasing cl+cif+args %V %V (%d)",
4300 ignored,
4301 (((closure_and_cif*)p)->data),
4302 SAME_OBJ(ignored,(((closure_and_cif*)p)->data)));
4303 */
4304 #ifdef MZ_PRECISE_GC
4305 GC_free_immobile_box((void**)(((closure_and_cif*)p)->data));
4306 #endif
4307 scheme_free_code(p);
4308 }
4309
4310 #ifdef MZ_USE_MZRT
free_cl_cif_queue_args(void * ignored,void * p)4311 static void free_cl_cif_queue_args(void *ignored, void *p)
4312 {
4313 void *data = ((closure_and_cif*)p)->data, *constant_result;
4314 void **q = (void **)data;
4315 data = q[0];
4316 constant_result = q[2];
4317 free(q);
4318 if (constant_result) free(constant_result);
4319 #ifdef MZ_PRECISE_GC
4320 GC_free_immobile_box((void**)data);
4321 #endif
4322 scheme_free_code(p);
4323 }
4324 #endif
4325
4326 /* In `curry` mode, just check arguments */
ffi_callback_or_curry(const char * who,int curry,int argc,Scheme_Object ** argv)4327 static Scheme_Object *ffi_callback_or_curry(const char *who, int curry, int argc, Scheme_Object **argv) {
4328 # define ARGPOS(n) ((n) - (curry ? 1 : 0))
4329 ffi_callback_struct *data;
4330 Scheme_Object *itypes = argv[ARGPOS(1)];
4331 Scheme_Object *otype = argv[ARGPOS(2)];
4332 Scheme_Object *sync;
4333 Scheme_Object *p, *base;
4334 ffi_abi abi;
4335 int is_atomic;
4336 int nargs, i, varargs_after;
4337 ffi_status ffi_ok;
4338 /* ffi_closure objects are problematic when used with a moving GC. The
4339 * problem is that memory that is GC-visible can move at any time. The
4340 * solution is to use an immobile-box, which an immobile pointer (in a simple
4341 * malloced block), which points to the ffi_callback_struct that contains the
4342 * relevant Racket call details. Another minor complexity is that an
4343 * immobile box serves as a reference for the GC, which means that nothing
4344 * will ever get collected: and the solution for this is to stick a weak-box
4345 * in the chain. Users need to be aware of GC issues, and need to keep a
4346 * reference to the callback object to avoid releasing the whole thing --
4347 * when that reference is lost, the ffi_callback_struct will be GCed, and a
4348 * finalizer will free() the malloced memory. Everything on the malloced
4349 * part is allocated in one block, to make it easy to free. The final layout
4350 * of the various objects is:
4351 *
4352 * <<======malloc======>> : <<===========scheme_malloc===============>>
4353 * :
4354 * ffi_closure <------------------------\
4355 * | | : |
4356 * | | : |
4357 * | \--> immobile ----> weak |
4358 * | box : box |
4359 * | : | |
4360 * | : | |
4361 * | : \--> ffi_callback_struct
4362 * | : | |
4363 * V : | \-----> Racket Closure
4364 * cif ---> atypes : |
4365 * : \--------> input/output types
4366 */
4367 GC_CAN_IGNORE ffi_type *rtype, **atypes;
4368 GC_CAN_IGNORE ffi_cif *cif;
4369 GC_CAN_IGNORE ffi_closure *cl;
4370 GC_CAN_IGNORE closure_and_cif *cl_cif_args;
4371 GC_CAN_IGNORE ffi_callback_t do_callback;
4372 GC_CAN_IGNORE void *callback_data;
4373 Scheme_Performance_State perf_state;
4374 # ifdef MZ_USE_MZRT
4375 int keep_queue = 0;
4376 void *constant_reply = NULL;
4377 int constant_reply_size = 0;
4378 # endif /* MZ_USE_MZRT */
4379
4380 if (!curry && !SCHEME_PROCP(argv[ARGPOS(0)]))
4381 scheme_wrong_contract(who, "procedure?", ARGPOS(0), argc, argv);
4382 nargs = scheme_proper_list_length(itypes);
4383 if (nargs < 0)
4384 scheme_wrong_contract(who, "list?", ARGPOS(1), argc, argv);
4385 if (NULL == (base = get_ctype_base(otype)))
4386 scheme_wrong_contract(who, "ctype?", ARGPOS(2), argc, argv);
4387 rtype = CTYPE_ARG_PRIMTYPE(base);
4388 abi = GET_ABI(who, ARGPOS(3));
4389 is_atomic = ((argc > ARGPOS(4)) && SCHEME_TRUEP(argv[ARGPOS(4)]));
4390 sync = (is_atomic ? scheme_true : NULL);
4391 if ((argc > ARGPOS(5))
4392 && !SCHEME_BOXP(argv[ARGPOS(5)])
4393 && !scheme_check_proc_arity2(NULL, 1, ARGPOS(5), argc, argv, 1))
4394 scheme_wrong_contract(who, "(or/c #f (procedure-arity-includes/c 0) box?)", ARGPOS(5), argc, argv);
4395 if (argc > ARGPOS(6))
4396 varargs_after = extract_varargs_after(who, argc, argv, ARGPOS(6), nargs);
4397 else
4398 varargs_after = -1;
4399
4400 if (curry) {
4401 /* all checks are done */
4402 return NULL;
4403 }
4404
4405 scheme_performance_record_start(&perf_state);
4406
4407 if (((argc > ARGPOS(5)) && SCHEME_TRUEP(argv[ARGPOS(5)]))) {
4408 # ifdef MZ_USE_MZRT
4409 if (!ffi_sync_queue) {
4410 mzrt_os_thread_id tid;
4411 void *sig_hand;
4412
4413 ffi_sync_queue = (FFI_Sync_Queue *)malloc(sizeof(FFI_Sync_Queue));
4414 tid = mz_proc_os_thread_self();
4415 ffi_sync_queue->orig_thread = tid;
4416 mzrt_mutex_create(&ffi_sync_queue->lock);
4417 sig_hand = scheme_get_signal_handle();
4418 ffi_sync_queue->sig_hand = sig_hand;
4419 ffi_sync_queue->callbacks = NULL;
4420 }
4421 if (SCHEME_BOXP(argv[ARGPOS(5)])) {
4422 /* when called in a foreign thread, return a constant */
4423 constant_reply_size = ctype_sizeof(otype);
4424 if (!constant_reply_size && SCHEME_VOIDP(SCHEME_BOX_VAL(argv[ARGPOS(5)]))) {
4425 /* void result */
4426 constant_reply = scheme_malloc_atomic(1);
4427 } else {
4428 /* non-void result */
4429 constant_reply = scheme_malloc_atomic(constant_reply_size);
4430 SCHEME2C(who, otype, constant_reply, 0, SCHEME_BOX_VAL(argv[ARGPOS(5)]), NULL, NULL, 0);
4431 }
4432 } else {
4433 /* when called in a foreign thread, queue a reply back here */
4434 sync = argv[ARGPOS(5)];
4435 if (is_atomic) sync = scheme_box(sync);
4436 constant_reply = NULL;
4437 constant_reply_size = 0;
4438 }
4439 keep_queue = 1;
4440 # endif /* MZ_USE_MZRT */
4441 do_callback = ffi_queue_callback;
4442 } else
4443 do_callback = ffi_do_callback;
4444
4445 /* malloc space for everything needed, so a single free gets rid of this */
4446 cl_cif_args = scheme_malloc_code(sizeof(closure_and_cif) + nargs*sizeof(ffi_cif*));
4447 scheme_thread_code_start_write();
4448 cl = &(cl_cif_args->closure); /* cl is the same as cl_cif_args */
4449 cif = &(cl_cif_args->cif);
4450 atypes = (ffi_type **)(((char*)cl_cif_args) + sizeof(closure_and_cif));
4451 for (i=0, p=itypes; i<nargs; i++, p=SCHEME_CDR(p)) {
4452 if (NULL == (base = get_ctype_base(SCHEME_CAR(p)))) {
4453 scheme_thread_code_end_write();
4454 scheme_wrong_contract(who, "(listof ctype?)", ARGPOS(1), argc, argv);
4455 }
4456 if (CTYPE_PRIMLABEL(base) == FOREIGN_void) {
4457 scheme_thread_code_end_write();
4458 wrong_void(who, SCHEME_CAR(p), 1, ARGPOS(1), argc, argv);
4459 }
4460 atypes[i] = CTYPE_ARG_PRIMTYPE(base);
4461 }
4462 if (varargs_after == -1) {
4463 if (ffi_prep_cif(cif, abi, nargs, rtype, atypes) != FFI_OK)
4464 scheme_signal_error("internal error: ffi_prep_cif did not return FFI_OK");
4465 } else {
4466 if (ffi_prep_cif_var(cif, abi, varargs_after, nargs, rtype, atypes) != FFI_OK)
4467 scheme_signal_error("internal error: ffi_prep_cif_var did not return FFI_OK");
4468 }
4469 scheme_thread_code_end_write();
4470 data = (ffi_callback_struct*)scheme_malloc_tagged(sizeof(ffi_callback_struct));
4471 data->so.type = ffi_callback_tag;
4472 data->callback = (cl_cif_args);
4473 data->proc = ((curry ? NULL : argv[ARGPOS(0)]));
4474 data->itypes = (argv[ARGPOS(1)]);
4475 data->otype = (argv[ARGPOS(2)]);
4476 data->sync = (sync);
4477 # ifdef MZ_PRECISE_GC
4478 {
4479 /* put data in immobile, weak box */
4480 GC_CAN_IGNORE void **tmp;
4481 tmp = GC_malloc_immobile_box(GC_malloc_weak_box(data, NULL, 0, 1));
4482 callback_data = (struct immobile_box*)tmp;
4483 }
4484 # else /* MZ_PRECISE_GC undefined */
4485 callback_data = (void*)data;
4486 # endif /* MZ_PRECISE_GC */
4487 # ifdef MZ_USE_MZRT
4488 if (keep_queue) {
4489 /* For ffi_queue_callback(), add a level of indirection in `data' to
4490 hold the place-specific `ffi_sync_queue'. Use
4491 `free_cl_cif_queue_args' to clean up this extra level. */
4492 GC_CAN_IGNORE void **tmp, *cr;
4493 if (constant_reply) {
4494 cr = malloc(constant_reply_size ? constant_reply_size : 1);
4495 memcpy(cr, constant_reply, constant_reply_size);
4496 constant_reply = cr;
4497 }
4498 tmp = (void **)malloc(sizeof(void*) * 4);
4499 tmp[0] = callback_data;
4500 tmp[1] = ffi_sync_queue;
4501 tmp[2] = constant_reply;
4502 tmp[3] = (void *)(intptr_t)constant_reply_size;
4503 callback_data = (void *)tmp;
4504 }
4505 # endif /* MZ_USE_MZRT */
4506 scheme_thread_code_start_write();
4507 cl_cif_args->data = callback_data;
4508 ffi_ok = ffi_prep_closure_loc(cl, cif, do_callback, (void*)(cl_cif_args->data), cl);
4509 scheme_thread_code_end_write();
4510 if (ffi_ok != FFI_OK)
4511 scheme_signal_error
4512 ("internal error: ffi_prep_closure did not return FFI_OK");
4513 # ifdef MZ_USE_MZRT
4514 if (keep_queue)
4515 scheme_register_finalizer(data, free_cl_cif_queue_args, cl_cif_args,
4516 NULL, NULL);
4517 else
4518 # endif /* MZ_USE_MZRT */
4519 scheme_register_finalizer(data, free_cl_cif_args, cl_cif_args, NULL, NULL);
4520
4521 scheme_performance_record_end("comp-ffi-back", &perf_state);
4522
4523 return (Scheme_Object*)data;
4524 #undef ARGPOS
4525 }
4526
4527 /* (ffi-callback scheme-proc in-types out-type [abi atomic? sync]) -> ffi-callback */
4528 /* the treatment of in-types and out-types is similar to that in ffi-call */
4529 /* the real work is done by ffi_do_callback above */
4530 #define MYNAME "ffi-callback"
foreign_ffi_callback(int argc,Scheme_Object * argv[])4531 static Scheme_Object *foreign_ffi_callback(int argc, Scheme_Object *argv[])
4532 {
4533 return ffi_callback_or_curry(MYNAME, 0, argc, argv);
4534 }
4535 #undef MYNAME
4536
make_ffi_callback_from_curried(int argc,Scheme_Object * argv[],Scheme_Object * self)4537 static Scheme_Object *make_ffi_callback_from_curried(int argc, Scheme_Object *argv[], Scheme_Object *self)
4538 {
4539 Scheme_Object *vec = SCHEME_PRIM_CLOSURE_ELS(self)[0];
4540 Scheme_Object *a[7];
4541 int c = SCHEME_VEC_SIZE(vec), i;
4542
4543 for (i = 0; i < c; i++) {
4544 a[i+1] = SCHEME_VEC_ELS(vec)[i];
4545 }
4546 a[0] = argv[0];
4547
4548 return ffi_callback_or_curry("make-ffi-callback", 0, c+1, a);
4549 }
4550
4551 /* (ffi-callback-maker in-types out-type [abi atomic? sync]) -> (proc -> ffi-callback) */
4552 /* Curried version of `ffi-callback`. Check arguments eagerly, but we don't do anything
4553 otherwise until a function is available. */
4554 #define MYNAME "ffi-callback-maker"
foreign_ffi_callback_maker(int argc,Scheme_Object * argv[])4555 static Scheme_Object *foreign_ffi_callback_maker(int argc, Scheme_Object *argv[])
4556 {
4557 int i;
4558 Scheme_Object *vec, *a[1];
4559
4560 (void)ffi_callback_or_curry(MYNAME, 1, argc, argv);
4561
4562 vec = scheme_make_vector(argc, NULL);
4563 for (i = 0; i < argc; i++) {
4564 SCHEME_VEC_ELS(vec)[i] = argv[i];
4565 }
4566 a[0] = vec;
4567
4568 return scheme_make_prim_closure_w_arity(make_ffi_callback_from_curried,
4569 1, a,
4570 "make-ffi-callback",
4571 1, 1);
4572 }
4573 #undef MYNAME
4574
4575 /*****************************************************************************/
4576
4577 #ifdef WINDOWS_DYNAMIC_LOAD
4578 typedef int *(*get_errno_ptr_t)(void);
4579 static get_errno_ptr_t get_errno_ptr;
4580 #endif /* WINDOWS_DYNAMIC_LOAD */
4581
save_errno_values(int kind)4582 static void save_errno_values(int kind)
4583 {
4584 Scheme_Thread *p = scheme_current_thread;
4585
4586 if (kind == 2) {
4587 intptr_t v = 0;
4588 # ifdef WINDOWS_DYNAMIC_LOAD
4589 v = GetLastError();
4590 # endif /* WINDOWS_DYNAMIC_LOAD */
4591 p->saved_errno = v;
4592 return;
4593 }
4594
4595 # ifdef WINDOWS_DYNAMIC_LOAD
4596 /* Depending on how Racket is compiled and linked, `errno` might
4597 not corresponds to the one from "MSVCRT.dll", which is likely
4598 to be the one that foreign code uses. Go get that one via
4599 _errno(), which returns a pointer to the current thread's
4600 `errno`. */
4601 if (!get_errno_ptr) {
4602 HMODULE hm;
4603 hm = LoadLibrary("msvcrt.dll");
4604 if (hm) {
4605 get_errno_ptr = (get_errno_ptr_t)GetProcAddress(hm, "_errno");
4606 }
4607 }
4608
4609 if (get_errno_ptr) {
4610 GC_CAN_IGNORE int *errno_ptr;
4611 errno_ptr = get_errno_ptr();
4612 errno = *errno_ptr;
4613 }
4614 # endif /* WINDOWS_DYNAMIC_LOAD */
4615
4616 p->saved_errno = errno;
4617 }
4618
4619 #define MYNAME "saved-errno"
foreign_saved_errno(int argc,Scheme_Object * argv[])4620 static Scheme_Object *foreign_saved_errno(int argc, Scheme_Object *argv[])
4621 {
4622 Scheme_Thread *p = scheme_current_thread;
4623 if (argc == 0) {
4624 return scheme_make_integer_value(p->saved_errno);
4625 } else {
4626 intptr_t v;
4627 if (!scheme_get_int_val(argv[0], &v)) {
4628 wrong_intptr(MYNAME, 0, argc, argv);
4629 }
4630 p->saved_errno = v;
4631 return scheme_void;
4632 }
4633 }
4634 #undef MYNAME
4635
4636 #define MYNAME "lookup-errno"
foreign_lookup_errno(int argc,Scheme_Object * argv[])4637 static Scheme_Object *foreign_lookup_errno(int argc, Scheme_Object *argv[])
4638 {
4639 Scheme_Object *v = argv[0];
4640 if (!SCHEME_SYMBOLP(v)) {
4641 scheme_wrong_contract(MYNAME, "symbol?", 0, argc, argv);
4642 return NULL;
4643 }
4644 if (SCHEME_SYM_WEIRDP(v))
4645 return scheme_false;
4646 # ifdef E2BIG
4647 if (!strcmp("E2BIG", SCHEME_SYM_VAL(v)))
4648 return scheme_make_integer(E2BIG);
4649 # endif /* E2BIG */
4650 # ifdef EACCES
4651 if (!strcmp("EACCES", SCHEME_SYM_VAL(v)))
4652 return scheme_make_integer(EACCES);
4653 # endif /* EACCES */
4654 # ifdef EADDRINUSE
4655 if (!strcmp("EADDRINUSE", SCHEME_SYM_VAL(v)))
4656 return scheme_make_integer(EADDRINUSE);
4657 # endif /* EADDRINUSE */
4658 # ifdef EADDRNOTAVAIL
4659 if (!strcmp("EADDRNOTAVAIL", SCHEME_SYM_VAL(v)))
4660 return scheme_make_integer(EADDRNOTAVAIL);
4661 # endif /* EADDRNOTAVAIL */
4662 # ifdef EAFNOSUPPORT
4663 if (!strcmp("EAFNOSUPPORT", SCHEME_SYM_VAL(v)))
4664 return scheme_make_integer(EAFNOSUPPORT);
4665 # endif /* EAFNOSUPPORT */
4666 # ifdef EAGAIN
4667 if (!strcmp("EAGAIN", SCHEME_SYM_VAL(v)))
4668 return scheme_make_integer(EAGAIN);
4669 # endif /* EAGAIN */
4670 # ifdef EALREADY
4671 if (!strcmp("EALREADY", SCHEME_SYM_VAL(v)))
4672 return scheme_make_integer(EALREADY);
4673 # endif /* EALREADY */
4674 # ifdef EBADF
4675 if (!strcmp("EBADF", SCHEME_SYM_VAL(v)))
4676 return scheme_make_integer(EBADF);
4677 # endif /* EBADF */
4678 # ifdef EBADMSG
4679 if (!strcmp("EBADMSG", SCHEME_SYM_VAL(v)))
4680 return scheme_make_integer(EBADMSG);
4681 # endif /* EBADMSG */
4682 # ifdef EBUSY
4683 if (!strcmp("EBUSY", SCHEME_SYM_VAL(v)))
4684 return scheme_make_integer(EBUSY);
4685 # endif /* EBUSY */
4686 # ifdef ECANCELED
4687 if (!strcmp("ECANCELED", SCHEME_SYM_VAL(v)))
4688 return scheme_make_integer(ECANCELED);
4689 # endif /* ECANCELED */
4690 # ifdef ECHILD
4691 if (!strcmp("ECHILD", SCHEME_SYM_VAL(v)))
4692 return scheme_make_integer(ECHILD);
4693 # endif /* ECHILD */
4694 # ifdef ECONNABORTED
4695 if (!strcmp("ECONNABORTED", SCHEME_SYM_VAL(v)))
4696 return scheme_make_integer(ECONNABORTED);
4697 # endif /* ECONNABORTED */
4698 # ifdef ECONNREFUSED
4699 if (!strcmp("ECONNREFUSED", SCHEME_SYM_VAL(v)))
4700 return scheme_make_integer(ECONNREFUSED);
4701 # endif /* ECONNREFUSED */
4702 # ifdef ECONNRESET
4703 if (!strcmp("ECONNRESET", SCHEME_SYM_VAL(v)))
4704 return scheme_make_integer(ECONNRESET);
4705 # endif /* ECONNRESET */
4706 # ifdef EDEADLK
4707 if (!strcmp("EDEADLK", SCHEME_SYM_VAL(v)))
4708 return scheme_make_integer(EDEADLK);
4709 # endif /* EDEADLK */
4710 # ifdef EDESTADDRREQ
4711 if (!strcmp("EDESTADDRREQ", SCHEME_SYM_VAL(v)))
4712 return scheme_make_integer(EDESTADDRREQ);
4713 # endif /* EDESTADDRREQ */
4714 # ifdef EDOM
4715 if (!strcmp("EDOM", SCHEME_SYM_VAL(v)))
4716 return scheme_make_integer(EDOM);
4717 # endif /* EDOM */
4718 # ifdef EDQUOT
4719 if (!strcmp("EDQUOT", SCHEME_SYM_VAL(v)))
4720 return scheme_make_integer(EDQUOT);
4721 # endif /* EDQUOT */
4722 # ifdef EEXIST
4723 if (!strcmp("EEXIST", SCHEME_SYM_VAL(v)))
4724 return scheme_make_integer(EEXIST);
4725 # endif /* EEXIST */
4726 # ifdef EFAULT
4727 if (!strcmp("EFAULT", SCHEME_SYM_VAL(v)))
4728 return scheme_make_integer(EFAULT);
4729 # endif /* EFAULT */
4730 # ifdef EFBIG
4731 if (!strcmp("EFBIG", SCHEME_SYM_VAL(v)))
4732 return scheme_make_integer(EFBIG);
4733 # endif /* EFBIG */
4734 # ifdef EHOSTUNREACH
4735 if (!strcmp("EHOSTUNREACH", SCHEME_SYM_VAL(v)))
4736 return scheme_make_integer(EHOSTUNREACH);
4737 # endif /* EHOSTUNREACH */
4738 # ifdef EIDRM
4739 if (!strcmp("EIDRM", SCHEME_SYM_VAL(v)))
4740 return scheme_make_integer(EIDRM);
4741 # endif /* EIDRM */
4742 # ifdef EILSEQ
4743 if (!strcmp("EILSEQ", SCHEME_SYM_VAL(v)))
4744 return scheme_make_integer(EILSEQ);
4745 # endif /* EILSEQ */
4746 # ifdef EINPROGRESS
4747 if (!strcmp("EINPROGRESS", SCHEME_SYM_VAL(v)))
4748 return scheme_make_integer(EINPROGRESS);
4749 # endif /* EINPROGRESS */
4750 # ifdef EINTR
4751 if (!strcmp("EINTR", SCHEME_SYM_VAL(v)))
4752 return scheme_make_integer(EINTR);
4753 # endif /* EINTR */
4754 # ifdef EINVAL
4755 if (!strcmp("EINVAL", SCHEME_SYM_VAL(v)))
4756 return scheme_make_integer(EINVAL);
4757 # endif /* EINVAL */
4758 # ifdef EIO
4759 if (!strcmp("EIO", SCHEME_SYM_VAL(v)))
4760 return scheme_make_integer(EIO);
4761 # endif /* EIO */
4762 # ifdef EISCONN
4763 if (!strcmp("EISCONN", SCHEME_SYM_VAL(v)))
4764 return scheme_make_integer(EISCONN);
4765 # endif /* EISCONN */
4766 # ifdef EISDIR
4767 if (!strcmp("EISDIR", SCHEME_SYM_VAL(v)))
4768 return scheme_make_integer(EISDIR);
4769 # endif /* EISDIR */
4770 # ifdef ELOOP
4771 if (!strcmp("ELOOP", SCHEME_SYM_VAL(v)))
4772 return scheme_make_integer(ELOOP);
4773 # endif /* ELOOP */
4774 # ifdef EMFILE
4775 if (!strcmp("EMFILE", SCHEME_SYM_VAL(v)))
4776 return scheme_make_integer(EMFILE);
4777 # endif /* EMFILE */
4778 # ifdef EMLINK
4779 if (!strcmp("EMLINK", SCHEME_SYM_VAL(v)))
4780 return scheme_make_integer(EMLINK);
4781 # endif /* EMLINK */
4782 # ifdef EMSGSIZE
4783 if (!strcmp("EMSGSIZE", SCHEME_SYM_VAL(v)))
4784 return scheme_make_integer(EMSGSIZE);
4785 # endif /* EMSGSIZE */
4786 # ifdef EMULTIHOP
4787 if (!strcmp("EMULTIHOP", SCHEME_SYM_VAL(v)))
4788 return scheme_make_integer(EMULTIHOP);
4789 # endif /* EMULTIHOP */
4790 # ifdef ENAMETOOLONG
4791 if (!strcmp("ENAMETOOLONG", SCHEME_SYM_VAL(v)))
4792 return scheme_make_integer(ENAMETOOLONG);
4793 # endif /* ENAMETOOLONG */
4794 # ifdef ENETDOWN
4795 if (!strcmp("ENETDOWN", SCHEME_SYM_VAL(v)))
4796 return scheme_make_integer(ENETDOWN);
4797 # endif /* ENETDOWN */
4798 # ifdef ENETRESET
4799 if (!strcmp("ENETRESET", SCHEME_SYM_VAL(v)))
4800 return scheme_make_integer(ENETRESET);
4801 # endif /* ENETRESET */
4802 # ifdef ENETUNREACH
4803 if (!strcmp("ENETUNREACH", SCHEME_SYM_VAL(v)))
4804 return scheme_make_integer(ENETUNREACH);
4805 # endif /* ENETUNREACH */
4806 # ifdef ENFILE
4807 if (!strcmp("ENFILE", SCHEME_SYM_VAL(v)))
4808 return scheme_make_integer(ENFILE);
4809 # endif /* ENFILE */
4810 # ifdef ENOBUFS
4811 if (!strcmp("ENOBUFS", SCHEME_SYM_VAL(v)))
4812 return scheme_make_integer(ENOBUFS);
4813 # endif /* ENOBUFS */
4814 # ifdef ENODATA
4815 if (!strcmp("ENODATA", SCHEME_SYM_VAL(v)))
4816 return scheme_make_integer(ENODATA);
4817 # endif /* ENODATA */
4818 # ifdef ENODEV
4819 if (!strcmp("ENODEV", SCHEME_SYM_VAL(v)))
4820 return scheme_make_integer(ENODEV);
4821 # endif /* ENODEV */
4822 # ifdef ENOENT
4823 if (!strcmp("ENOENT", SCHEME_SYM_VAL(v)))
4824 return scheme_make_integer(ENOENT);
4825 # endif /* ENOENT */
4826 # ifdef ENOEXEC
4827 if (!strcmp("ENOEXEC", SCHEME_SYM_VAL(v)))
4828 return scheme_make_integer(ENOEXEC);
4829 # endif /* ENOEXEC */
4830 # ifdef ENOLCK
4831 if (!strcmp("ENOLCK", SCHEME_SYM_VAL(v)))
4832 return scheme_make_integer(ENOLCK);
4833 # endif /* ENOLCK */
4834 # ifdef ENOLINK
4835 if (!strcmp("ENOLINK", SCHEME_SYM_VAL(v)))
4836 return scheme_make_integer(ENOLINK);
4837 # endif /* ENOLINK */
4838 # ifdef ENOMEM
4839 if (!strcmp("ENOMEM", SCHEME_SYM_VAL(v)))
4840 return scheme_make_integer(ENOMEM);
4841 # endif /* ENOMEM */
4842 # ifdef ENOMSG
4843 if (!strcmp("ENOMSG", SCHEME_SYM_VAL(v)))
4844 return scheme_make_integer(ENOMSG);
4845 # endif /* ENOMSG */
4846 # ifdef ENOPROTOOPT
4847 if (!strcmp("ENOPROTOOPT", SCHEME_SYM_VAL(v)))
4848 return scheme_make_integer(ENOPROTOOPT);
4849 # endif /* ENOPROTOOPT */
4850 # ifdef ENOSPC
4851 if (!strcmp("ENOSPC", SCHEME_SYM_VAL(v)))
4852 return scheme_make_integer(ENOSPC);
4853 # endif /* ENOSPC */
4854 # ifdef ENOSR
4855 if (!strcmp("ENOSR", SCHEME_SYM_VAL(v)))
4856 return scheme_make_integer(ENOSR);
4857 # endif /* ENOSR */
4858 # ifdef ENOSTR
4859 if (!strcmp("ENOSTR", SCHEME_SYM_VAL(v)))
4860 return scheme_make_integer(ENOSTR);
4861 # endif /* ENOSTR */
4862 # ifdef ENOSYS
4863 if (!strcmp("ENOSYS", SCHEME_SYM_VAL(v)))
4864 return scheme_make_integer(ENOSYS);
4865 # endif /* ENOSYS */
4866 # ifdef ENOTCONN
4867 if (!strcmp("ENOTCONN", SCHEME_SYM_VAL(v)))
4868 return scheme_make_integer(ENOTCONN);
4869 # endif /* ENOTCONN */
4870 # ifdef ENOTDIR
4871 if (!strcmp("ENOTDIR", SCHEME_SYM_VAL(v)))
4872 return scheme_make_integer(ENOTDIR);
4873 # endif /* ENOTDIR */
4874 # ifdef ENOTEMPTY
4875 if (!strcmp("ENOTEMPTY", SCHEME_SYM_VAL(v)))
4876 return scheme_make_integer(ENOTEMPTY);
4877 # endif /* ENOTEMPTY */
4878 # ifdef ENOTRECOVERABLE
4879 if (!strcmp("ENOTRECOVERABLE", SCHEME_SYM_VAL(v)))
4880 return scheme_make_integer(ENOTRECOVERABLE);
4881 # endif /* ENOTRECOVERABLE */
4882 # ifdef ENOTSOCK
4883 if (!strcmp("ENOTSOCK", SCHEME_SYM_VAL(v)))
4884 return scheme_make_integer(ENOTSOCK);
4885 # endif /* ENOTSOCK */
4886 # ifdef ENOTSUP
4887 if (!strcmp("ENOTSUP", SCHEME_SYM_VAL(v)))
4888 return scheme_make_integer(ENOTSUP);
4889 # endif /* ENOTSUP */
4890 # ifdef ENOTTY
4891 if (!strcmp("ENOTTY", SCHEME_SYM_VAL(v)))
4892 return scheme_make_integer(ENOTTY);
4893 # endif /* ENOTTY */
4894 # ifdef ENXIO
4895 if (!strcmp("ENXIO", SCHEME_SYM_VAL(v)))
4896 return scheme_make_integer(ENXIO);
4897 # endif /* ENXIO */
4898 # ifdef EOPNOTSUPP
4899 if (!strcmp("EOPNOTSUPP", SCHEME_SYM_VAL(v)))
4900 return scheme_make_integer(EOPNOTSUPP);
4901 # endif /* EOPNOTSUPP */
4902 # ifdef EOVERFLOW
4903 if (!strcmp("EOVERFLOW", SCHEME_SYM_VAL(v)))
4904 return scheme_make_integer(EOVERFLOW);
4905 # endif /* EOVERFLOW */
4906 # ifdef EOWNERDEAD
4907 if (!strcmp("EOWNERDEAD", SCHEME_SYM_VAL(v)))
4908 return scheme_make_integer(EOWNERDEAD);
4909 # endif /* EOWNERDEAD */
4910 # ifdef EPERM
4911 if (!strcmp("EPERM", SCHEME_SYM_VAL(v)))
4912 return scheme_make_integer(EPERM);
4913 # endif /* EPERM */
4914 # ifdef EPIPE
4915 if (!strcmp("EPIPE", SCHEME_SYM_VAL(v)))
4916 return scheme_make_integer(EPIPE);
4917 # endif /* EPIPE */
4918 # ifdef EPROTO
4919 if (!strcmp("EPROTO", SCHEME_SYM_VAL(v)))
4920 return scheme_make_integer(EPROTO);
4921 # endif /* EPROTO */
4922 # ifdef EPROTONOSUPPORT
4923 if (!strcmp("EPROTONOSUPPORT", SCHEME_SYM_VAL(v)))
4924 return scheme_make_integer(EPROTONOSUPPORT);
4925 # endif /* EPROTONOSUPPORT */
4926 # ifdef EPROTOTYPE
4927 if (!strcmp("EPROTOTYPE", SCHEME_SYM_VAL(v)))
4928 return scheme_make_integer(EPROTOTYPE);
4929 # endif /* EPROTOTYPE */
4930 # ifdef ERANGE
4931 if (!strcmp("ERANGE", SCHEME_SYM_VAL(v)))
4932 return scheme_make_integer(ERANGE);
4933 # endif /* ERANGE */
4934 # ifdef EROFS
4935 if (!strcmp("EROFS", SCHEME_SYM_VAL(v)))
4936 return scheme_make_integer(EROFS);
4937 # endif /* EROFS */
4938 # ifdef ESPIPE
4939 if (!strcmp("ESPIPE", SCHEME_SYM_VAL(v)))
4940 return scheme_make_integer(ESPIPE);
4941 # endif /* ESPIPE */
4942 # ifdef ESRCH
4943 if (!strcmp("ESRCH", SCHEME_SYM_VAL(v)))
4944 return scheme_make_integer(ESRCH);
4945 # endif /* ESRCH */
4946 # ifdef ESTALE
4947 if (!strcmp("ESTALE", SCHEME_SYM_VAL(v)))
4948 return scheme_make_integer(ESTALE);
4949 # endif /* ESTALE */
4950 # ifdef ETIME
4951 if (!strcmp("ETIME", SCHEME_SYM_VAL(v)))
4952 return scheme_make_integer(ETIME);
4953 # endif /* ETIME */
4954 # ifdef ETIMEDOUT
4955 if (!strcmp("ETIMEDOUT", SCHEME_SYM_VAL(v)))
4956 return scheme_make_integer(ETIMEDOUT);
4957 # endif /* ETIMEDOUT */
4958 # ifdef ETXTBSY
4959 if (!strcmp("ETXTBSY", SCHEME_SYM_VAL(v)))
4960 return scheme_make_integer(ETXTBSY);
4961 # endif /* ETXTBSY */
4962 # ifdef EWOULDBLOCK
4963 if (!strcmp("EWOULDBLOCK", SCHEME_SYM_VAL(v)))
4964 return scheme_make_integer(EWOULDBLOCK);
4965 # endif /* EWOULDBLOCK */
4966 # ifdef EXDEV
4967 if (!strcmp("EXDEV", SCHEME_SYM_VAL(v)))
4968 return scheme_make_integer(EXDEV);
4969 # endif /* EXDEV */
4970 return scheme_false;
4971 }
4972 #undef MYNAME
4973
4974 /*****************************************************************************/
4975
4976 /* (make-late-will-executor) -> #<will-executor> */
4977 #define MYNAME "make-late-will-executor"
foreign_make_late_will_executor(int argc,Scheme_Object * argv[])4978 static Scheme_Object *foreign_make_late_will_executor(int argc, Scheme_Object *argv[])
4979 {
4980 return scheme_make_late_will_executor();
4981 }
4982 #undef MYNAME
4983
4984 /* (make-late-weak-box val) -> #<weak-box> */
4985 #define MYNAME "make-late-weak-box"
foreign_make_late_weak_box(int argc,Scheme_Object * argv[])4986 static Scheme_Object *foreign_make_late_weak_box(int argc, Scheme_Object *argv[])
4987 {
4988 return scheme_make_late_weak_box(argv[0]);
4989 }
4990 #undef MYNAME
4991
4992 /* (make-late-weak-hasheq) -> #<hash> */
4993 #define MYNAME "make-late-weak-hasheq"
foreign_make_late_weak_hasheq(int argc,Scheme_Object * argv[])4994 static Scheme_Object *foreign_make_late_weak_hasheq(int argc, Scheme_Object *argv[])
4995 {
4996 return (Scheme_Object *)scheme_make_bucket_table(20, SCHEME_hash_late_weak_ptr);
4997 }
4998 #undef MYNAME
4999
5000 /*****************************************************************************/
5001
ctype_printer(Scheme_Object * ctype,int dis,Scheme_Print_Params * pp)5002 void ctype_printer(Scheme_Object *ctype, int dis, Scheme_Print_Params *pp)
5003 {
5004 char *str;
5005 if (CTYPE_PRIMP(ctype)) {
5006 scheme_print_bytes(pp, "#<ctype:", 0, 8);
5007 ctype = CTYPE_BASETYPE(ctype);
5008 if (SCHEME_SYMBOLP(ctype)) {
5009 str = SCHEME_SYM_VAL(ctype);
5010 scheme_print_bytes(pp, str, 0, strlen(str));
5011 } else {
5012 scheme_print_bytes(pp, "cstruct", 0, 7);
5013 }
5014 scheme_print_bytes(pp, ">", 0, 1);
5015 } else {
5016 scheme_print_bytes(pp, "#<ctype>", 0, 8);
5017 }
5018 }
5019
5020 /*****************************************************************************/
5021 /* Initialization */
5022
5023 /* types need to be initialized before places can spawn
5024 * types become entries in the GC mark and fixup tables
5025 * this function should initialize read-only globals that can be
5026 * shared without locking */
scheme_init_foreign_globals()5027 void scheme_init_foreign_globals()
5028 {
5029 ffi_lib_tag = scheme_make_type("<ffi-lib>");
5030 ffi_obj_tag = scheme_make_type("<ffi-obj>");
5031 ;
5032 ffi_callback_tag = scheme_make_type("<ffi-callback>");
5033 # ifdef MZ_PRECISE_GC
5034 GC_register_traversers(ffi_lib_tag, ffi_lib_SIZE, ffi_lib_MARK, ffi_lib_FIXUP, 1, 0);
5035 GC_register_traversers(ffi_obj_tag, ffi_obj_SIZE, ffi_obj_MARK, ffi_obj_FIXUP, 1, 0);
5036 GC_register_traversers(ctype_tag, ctype_SIZE, ctype_MARK, ctype_FIXUP, 1, 0);
5037 GC_register_traversers(ffi_callback_tag, ffi_callback_SIZE, ffi_callback_MARK, ffi_callback_FIXUP, 1, 0);
5038 # endif /* MZ_PRECISE_GC */
5039 scheme_set_type_printer(scheme_ctype_type, ctype_printer);
5040 MZ_REGISTER_STATIC(nonatomic_sym);
5041 nonatomic_sym = scheme_intern_symbol("nonatomic");
5042 MZ_REGISTER_STATIC(atomic_sym);
5043 atomic_sym = scheme_intern_symbol("atomic");
5044 MZ_REGISTER_STATIC(stubborn_sym);
5045 stubborn_sym = scheme_intern_symbol("stubborn");
5046 MZ_REGISTER_STATIC(uncollectable_sym);
5047 uncollectable_sym = scheme_intern_symbol("uncollectable");
5048 MZ_REGISTER_STATIC(eternal_sym);
5049 eternal_sym = scheme_intern_symbol("eternal");
5050 MZ_REGISTER_STATIC(interior_sym);
5051 interior_sym = scheme_intern_symbol("interior");
5052 MZ_REGISTER_STATIC(atomic_interior_sym);
5053 atomic_interior_sym = scheme_intern_symbol("atomic-interior");
5054 MZ_REGISTER_STATIC(raw_sym);
5055 raw_sym = scheme_intern_symbol("raw");
5056 MZ_REGISTER_STATIC(tagged_sym);
5057 tagged_sym = scheme_intern_symbol("tagged");
5058 MZ_REGISTER_STATIC(fail_ok_sym);
5059 fail_ok_sym = scheme_intern_symbol("fail-ok");
5060 MZ_REGISTER_STATIC(default_sym);
5061 default_sym = scheme_intern_symbol("default");
5062 MZ_REGISTER_STATIC(stdcall_sym);
5063 stdcall_sym = scheme_intern_symbol("stdcall");
5064 MZ_REGISTER_STATIC(sysv_sym);
5065 sysv_sym = scheme_intern_symbol("sysv");
5066 MZ_REGISTER_STATIC(abs_sym);
5067 abs_sym = scheme_intern_symbol("abs");
5068
5069 MZ_REGISTER_STATIC(ffi_name);
5070 ffi_name = scheme_make_byte_string("ffi:proc");
5071 }
5072
scheme_init_foreign_places()5073 void scheme_init_foreign_places() {
5074 MZ_REGISTER_STATIC(opened_libs);
5075 opened_libs = scheme_make_hash_table(SCHEME_hash_string);
5076 #ifdef MZ_USE_PLACES
5077 if (!orig_place_mutex) {
5078 mzrt_mutex_create(&orig_place_mutex);
5079 orig_place_signal_handle = scheme_get_signal_handle();
5080 }
5081 #endif
5082 }
5083
scheme_make_inline_noncm_prim(Scheme_Prim * prim,const char * name,mzshort mina,mzshort maxa)5084 static Scheme_Object *scheme_make_inline_noncm_prim(Scheme_Prim *prim,
5085 const char *name,
5086 mzshort mina, mzshort maxa)
5087 {
5088 Scheme_Object *p;
5089 int flags = 0;
5090
5091 p = scheme_make_noncm_prim(prim, name, mina, maxa);
5092
5093 if ((mina <= 1) && (maxa >= 1))
5094 flags |= SCHEME_PRIM_IS_UNARY_INLINED;
5095 if ((mina <= 2) && (maxa >= 2))
5096 flags |= SCHEME_PRIM_IS_BINARY_INLINED;
5097 if ((mina <= 0) || (maxa > 2))
5098 flags |= SCHEME_PRIM_IS_NARY_INLINED;
5099
5100 SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(flags);
5101
5102 return p;
5103 }
5104
5105 Scheme_Object *scheme_pointer_ctype;
5106 Scheme_Object *scheme_float_ctype;
5107 Scheme_Object *scheme_double_ctype;
5108 Scheme_Object *scheme_int8_ctype;
5109 Scheme_Object *scheme_uint8_ctype;
5110 Scheme_Object *scheme_int16_ctype;
5111 Scheme_Object *scheme_uint16_ctype;
5112 Scheme_Object *scheme_int32_ctype;
5113 Scheme_Object *scheme_uint32_ctype;
5114 Scheme_Object *scheme_int64_ctype;
5115 Scheme_Object *scheme_uint64_ctype;
5116
scheme_init_foreign(Scheme_Startup_Env * env)5117 void scheme_init_foreign(Scheme_Startup_Env *env)
5118 {
5119 ctype_struct *t;
5120 Scheme_Object *s;
5121 memcpy(&ffi_type_gcpointer, &ffi_type_pointer, sizeof(ffi_type_pointer));
5122 scheme_switch_prim_instance(env, "#%foreign");
5123 scheme_addto_prim_instance("ffi-lib?",
5124 scheme_make_immed_prim(foreign_ffi_lib_p, "ffi-lib?", 1, 1), env);
5125 scheme_addto_prim_instance("ffi-lib",
5126 scheme_make_noncm_prim(foreign_ffi_lib, "ffi-lib", 1, 3), env);
5127 scheme_addto_prim_instance("ffi-lib-name",
5128 scheme_make_noncm_prim(foreign_ffi_lib_name, "ffi-lib-name", 1, 1), env);
5129 scheme_addto_prim_instance("ffi-lib-unload",
5130 scheme_make_noncm_prim(foreign_ffi_lib_unload, "ffi-lib-unload", 1, 1), env);
5131 scheme_addto_prim_instance("ffi-obj?",
5132 scheme_make_immed_prim(foreign_ffi_obj_p, "ffi-obj?", 1, 1), env);
5133 scheme_addto_prim_instance("ffi-obj",
5134 scheme_make_noncm_prim(foreign_ffi_obj, "ffi-obj", 2, 2), env);
5135 scheme_addto_prim_instance("ffi-obj-lib",
5136 scheme_make_immed_prim(foreign_ffi_obj_lib, "ffi-obj-lib", 1, 1), env);
5137 scheme_addto_prim_instance("ffi-obj-name",
5138 scheme_make_immed_prim(foreign_ffi_obj_name, "ffi-obj-name", 1, 1), env);
5139 scheme_addto_prim_instance("ctype?",
5140 scheme_make_immed_prim(foreign_ctype_p, "ctype?", 1, 1), env);
5141 scheme_addto_prim_instance("ctype-basetype",
5142 scheme_make_immed_prim(foreign_ctype_basetype, "ctype-basetype", 1, 1), env);
5143 scheme_addto_prim_instance("ctype-scheme->c",
5144 scheme_make_immed_prim(foreign_ctype_scheme_to_c, "ctype-scheme->c", 1, 1), env);
5145 scheme_addto_prim_instance("ctype-c->scheme",
5146 scheme_make_immed_prim(foreign_ctype_c_to_scheme, "ctype-c->scheme", 1, 1), env);
5147 scheme_addto_prim_instance("make-ctype",
5148 scheme_make_noncm_prim(foreign_make_ctype, "make-ctype", 3, 3), env);
5149 scheme_addto_prim_instance("make-cstruct-type",
5150 scheme_make_noncm_prim(foreign_make_cstruct_type, "make-cstruct-type", 1, 4), env);
5151 scheme_addto_prim_instance("make-array-type",
5152 scheme_make_noncm_prim(foreign_make_array_type, "make-array-type", 2, 2), env);
5153 scheme_addto_prim_instance("make-union-type",
5154 scheme_make_noncm_prim(foreign_make_union_type, "make-union-type", 1, -1), env);
5155 scheme_addto_prim_instance("ffi-callback?",
5156 scheme_make_immed_prim(foreign_ffi_callback_p, "ffi-callback?", 1, 1), env);
5157 scheme_addto_prim_instance("cpointer?",
5158 scheme_make_immed_prim(foreign_cpointer_p, "cpointer?", 1, 1), env);
5159 scheme_addto_prim_instance("cpointer-tag",
5160 scheme_make_inline_noncm_prim(foreign_cpointer_tag, "cpointer-tag", 1, 1), env);
5161 scheme_addto_prim_instance("set-cpointer-tag!",
5162 scheme_make_inline_noncm_prim(foreign_set_cpointer_tag_bang, "set-cpointer-tag!", 2, 2), env);
5163 scheme_addto_prim_instance("cpointer-gcable?",
5164 scheme_make_noncm_prim(foreign_cpointer_gcable_p, "cpointer-gcable?", 1, 1), env);
5165 scheme_addto_prim_instance("ctype-sizeof",
5166 scheme_make_immed_prim(foreign_ctype_sizeof, "ctype-sizeof", 1, 1), env);
5167 scheme_addto_prim_instance("ctype-alignof",
5168 scheme_make_immed_prim(foreign_ctype_alignof, "ctype-alignof", 1, 1), env);
5169 scheme_addto_prim_instance("compiler-sizeof",
5170 scheme_make_immed_prim(foreign_compiler_sizeof, "compiler-sizeof", 1, 1), env);
5171 scheme_addto_prim_instance("malloc",
5172 scheme_make_noncm_prim(foreign_malloc, "malloc", 1, 5), env);
5173 scheme_addto_prim_instance("end-stubborn-change",
5174 scheme_make_noncm_prim(foreign_end_stubborn_change, "end-stubborn-change", 1, 1), env);
5175 scheme_addto_prim_instance("free",
5176 scheme_make_noncm_prim(foreign_free, "free", 1, 1), env);
5177 scheme_addto_prim_instance("malloc-immobile-cell",
5178 scheme_make_immed_prim(foreign_malloc_immobile_cell, "malloc-immobile-cell", 1, 1), env);
5179 scheme_addto_prim_instance("free-immobile-cell",
5180 scheme_make_noncm_prim(foreign_free_immobile_cell, "free-immobile-cell", 1, 1), env);
5181 scheme_addto_prim_instance("ptr-add",
5182 scheme_make_noncm_prim(foreign_ptr_add, "ptr-add", 2, 3), env);
5183 scheme_addto_prim_instance("ptr-add!",
5184 scheme_make_noncm_prim(foreign_ptr_add_bang, "ptr-add!", 2, 3), env);
5185 scheme_addto_prim_instance("offset-ptr?",
5186 scheme_make_noncm_prim(foreign_offset_ptr_p, "offset-ptr?", 1, 1), env);
5187 scheme_addto_prim_instance("ptr-offset",
5188 scheme_make_noncm_prim(foreign_ptr_offset, "ptr-offset", 1, 1), env);
5189 scheme_addto_prim_instance("set-ptr-offset!",
5190 scheme_make_noncm_prim(foreign_set_ptr_offset_bang, "set-ptr-offset!", 2, 3), env);
5191 scheme_addto_prim_instance("vector->cpointer",
5192 scheme_make_immed_prim(foreign_vector_to_cpointer, "vector->cpointer", 1, 1), env);
5193 scheme_addto_prim_instance("flvector->cpointer",
5194 scheme_make_immed_prim(foreign_flvector_to_cpointer, "flvector->cpointer", 1, 1), env);
5195 scheme_addto_prim_instance("extflvector->cpointer",
5196 scheme_make_immed_prim(foreign_extflvector_to_cpointer, "extflvector->cpointer", 1, 1), env);
5197 scheme_addto_prim_instance("memset",
5198 scheme_make_noncm_prim(foreign_memset, "memset", 3, 5), env);
5199 scheme_addto_prim_instance("memmove",
5200 scheme_make_noncm_prim(foreign_memmove, "memmove", 3, 6), env);
5201 scheme_addto_prim_instance("memcpy",
5202 scheme_make_noncm_prim(foreign_memcpy, "memcpy", 3, 6), env);
5203 scheme_addto_prim_instance("ptr-ref",
5204 scheme_make_inline_noncm_prim(foreign_ptr_ref, "ptr-ref", 2, 4), env);
5205 scheme_addto_prim_instance("ptr-set!",
5206 scheme_make_inline_noncm_prim(foreign_ptr_set_bang, "ptr-set!", 3, 5), env);
5207 scheme_addto_prim_instance("ptr-equal?",
5208 scheme_make_noncm_prim(foreign_ptr_equal_p, "ptr-equal?", 2, 2), env);
5209 scheme_addto_prim_instance("make-sized-byte-string",
5210 scheme_make_noncm_prim(foreign_make_sized_byte_string, "make-sized-byte-string", 2, 2), env);
5211 scheme_addto_prim_instance("ffi-call",
5212 scheme_make_noncm_prim(foreign_ffi_call, "ffi-call", 3, 10), env);
5213 scheme_addto_prim_instance("ffi-call-maker",
5214 scheme_make_noncm_prim(foreign_ffi_call_maker, "ffi-call-maker", 2, 9), env);
5215 scheme_addto_prim_instance("ffi-callback",
5216 scheme_make_noncm_prim(foreign_ffi_callback, "ffi-callback", 3, 6), env);
5217 scheme_addto_prim_instance("ffi-callback-maker",
5218 scheme_make_noncm_prim(foreign_ffi_callback_maker, "ffi-callback-maker", 2, 6), env);
5219 scheme_addto_prim_instance("saved-errno",
5220 scheme_make_immed_prim(foreign_saved_errno, "saved-errno", 0, 1), env);
5221 scheme_addto_prim_instance("lookup-errno",
5222 scheme_make_immed_prim(foreign_lookup_errno, "lookup-errno", 1, 1), env);
5223 scheme_addto_prim_instance("make-late-will-executor",
5224 scheme_make_immed_prim(foreign_make_late_will_executor, "make-late-will-executor", 0, 0), env);
5225 scheme_addto_prim_instance("make-late-weak-box",
5226 scheme_make_immed_prim(foreign_make_late_weak_box, "make-late-weak-box", 1, 1), env);
5227 scheme_addto_prim_instance("make-late-weak-hasheq",
5228 scheme_make_immed_prim(foreign_make_late_weak_hasheq, "make-late-weak-hasheq", 0, 0), env);
5229 s = scheme_intern_symbol("void");
5230 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5231 t->so.type = ctype_tag;
5232 t->basetype = (s);
5233 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_void));
5234 t->c_to_scheme = ((Scheme_Object*)FOREIGN_void);
5235 scheme_addto_prim_instance("_void", (Scheme_Object*)t, env);
5236 s = scheme_intern_symbol("int8");
5237 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5238 t->so.type = ctype_tag;
5239 t->basetype = (s);
5240 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint8));
5241 t->c_to_scheme = ((Scheme_Object*)FOREIGN_int8);
5242 REGISTER_SO(scheme_int8_ctype);
5243 scheme_int8_ctype = (Scheme_Object *)t;
5244 scheme_addto_prim_instance("_int8", (Scheme_Object*)t, env);
5245 s = scheme_intern_symbol("uint8");
5246 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5247 t->so.type = ctype_tag;
5248 t->basetype = (s);
5249 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint8));
5250 t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint8);
5251 REGISTER_SO(scheme_uint8_ctype);
5252 scheme_uint8_ctype = (Scheme_Object *)t;
5253 scheme_addto_prim_instance("_uint8", (Scheme_Object*)t, env);
5254 s = scheme_intern_symbol("int16");
5255 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5256 t->so.type = ctype_tag;
5257 t->basetype = (s);
5258 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint16));
5259 t->c_to_scheme = ((Scheme_Object*)FOREIGN_int16);
5260 REGISTER_SO(scheme_int16_ctype);
5261 scheme_int16_ctype = (Scheme_Object *)t;
5262 scheme_addto_prim_instance("_int16", (Scheme_Object*)t, env);
5263 s = scheme_intern_symbol("uint16");
5264 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5265 t->so.type = ctype_tag;
5266 t->basetype = (s);
5267 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint16));
5268 t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint16);
5269 REGISTER_SO(scheme_uint16_ctype);
5270 scheme_uint16_ctype = (Scheme_Object *)t;
5271 scheme_addto_prim_instance("_uint16", (Scheme_Object*)t, env);
5272 s = scheme_intern_symbol("int32");
5273 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5274 t->so.type = ctype_tag;
5275 t->basetype = (s);
5276 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint32));
5277 t->c_to_scheme = ((Scheme_Object*)FOREIGN_int32);
5278 REGISTER_SO(scheme_int32_ctype);
5279 scheme_int32_ctype = (Scheme_Object *)t;
5280 scheme_addto_prim_instance("_int32", (Scheme_Object*)t, env);
5281 s = scheme_intern_symbol("uint32");
5282 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5283 t->so.type = ctype_tag;
5284 t->basetype = (s);
5285 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint32));
5286 t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint32);
5287 REGISTER_SO(scheme_uint32_ctype);
5288 scheme_uint32_ctype = (Scheme_Object *)t;
5289 scheme_addto_prim_instance("_uint32", (Scheme_Object*)t, env);
5290 s = scheme_intern_symbol("int64");
5291 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5292 t->so.type = ctype_tag;
5293 t->basetype = (s);
5294 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint64));
5295 t->c_to_scheme = ((Scheme_Object*)FOREIGN_int64);
5296 REGISTER_SO(scheme_int64_ctype);
5297 scheme_int64_ctype = (Scheme_Object *)t;
5298 scheme_addto_prim_instance("_int64", (Scheme_Object*)t, env);
5299 s = scheme_intern_symbol("uint64");
5300 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5301 t->so.type = ctype_tag;
5302 t->basetype = (s);
5303 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint64));
5304 t->c_to_scheme = ((Scheme_Object*)FOREIGN_uint64);
5305 REGISTER_SO(scheme_uint64_ctype);
5306 scheme_uint64_ctype = (Scheme_Object *)t;
5307 scheme_addto_prim_instance("_uint64", (Scheme_Object*)t, env);
5308 s = scheme_intern_symbol("fixint");
5309 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5310 t->so.type = ctype_tag;
5311 t->basetype = (s);
5312 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint32));
5313 t->c_to_scheme = ((Scheme_Object*)FOREIGN_fixint);
5314 scheme_addto_prim_instance("_fixint", (Scheme_Object*)t, env);
5315 s = scheme_intern_symbol("ufixint");
5316 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5317 t->so.type = ctype_tag;
5318 t->basetype = (s);
5319 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_uint32));
5320 t->c_to_scheme = ((Scheme_Object*)FOREIGN_ufixint);
5321 scheme_addto_prim_instance("_ufixint", (Scheme_Object*)t, env);
5322 s = scheme_intern_symbol("fixnum");
5323 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5324 t->so.type = ctype_tag;
5325 t->basetype = (s);
5326 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_smzintptr));
5327 t->c_to_scheme = ((Scheme_Object*)FOREIGN_fixnum);
5328 scheme_addto_prim_instance("_fixnum", (Scheme_Object*)t, env);
5329 s = scheme_intern_symbol("ufixnum");
5330 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5331 t->so.type = ctype_tag;
5332 t->basetype = (s);
5333 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_umzintptr));
5334 t->c_to_scheme = ((Scheme_Object*)FOREIGN_ufixnum);
5335 scheme_addto_prim_instance("_ufixnum", (Scheme_Object*)t, env);
5336 s = scheme_intern_symbol("float");
5337 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5338 t->so.type = ctype_tag;
5339 t->basetype = (s);
5340 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_float));
5341 t->c_to_scheme = ((Scheme_Object*)FOREIGN_float);
5342 REGISTER_SO(scheme_float_ctype);
5343 scheme_float_ctype = (Scheme_Object *)t;
5344 scheme_addto_prim_instance("_float", (Scheme_Object*)t, env);
5345 s = scheme_intern_symbol("double");
5346 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5347 t->so.type = ctype_tag;
5348 t->basetype = (s);
5349 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_double));
5350 t->c_to_scheme = ((Scheme_Object*)FOREIGN_double);
5351 REGISTER_SO(scheme_double_ctype);
5352 scheme_double_ctype = (Scheme_Object *)t;
5353 scheme_addto_prim_instance("_double", (Scheme_Object*)t, env);
5354 s = scheme_intern_symbol("longdouble");
5355 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5356 t->so.type = ctype_tag;
5357 t->basetype = (s);
5358 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_slongdouble));
5359 t->c_to_scheme = ((Scheme_Object*)FOREIGN_longdouble);
5360 scheme_addto_prim_instance("_longdouble", (Scheme_Object*)t, env);
5361 s = scheme_intern_symbol("double*");
5362 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5363 t->so.type = ctype_tag;
5364 t->basetype = (s);
5365 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_double));
5366 t->c_to_scheme = ((Scheme_Object*)FOREIGN_doubleS);
5367 scheme_addto_prim_instance("_double*", (Scheme_Object*)t, env);
5368 s = scheme_intern_symbol("bool");
5369 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5370 t->so.type = ctype_tag;
5371 t->basetype = (s);
5372 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_sint));
5373 t->c_to_scheme = ((Scheme_Object*)FOREIGN_bool);
5374 scheme_addto_prim_instance("_bool", (Scheme_Object*)t, env);
5375 s = scheme_intern_symbol("stdbool");
5376 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5377 t->so.type = ctype_tag;
5378 t->basetype = (s);
5379 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_stdbool));
5380 t->c_to_scheme = ((Scheme_Object*)FOREIGN_stdbool);
5381 scheme_addto_prim_instance("_stdbool", (Scheme_Object*)t, env);
5382 s = scheme_intern_symbol("string/ucs-4");
5383 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5384 t->so.type = ctype_tag;
5385 t->basetype = (s);
5386 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5387 t->c_to_scheme = ((Scheme_Object*)FOREIGN_string_ucs_4);
5388 scheme_addto_prim_instance("_string/ucs-4", (Scheme_Object*)t, env);
5389 s = scheme_intern_symbol("string/utf-16");
5390 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5391 t->so.type = ctype_tag;
5392 t->basetype = (s);
5393 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5394 t->c_to_scheme = ((Scheme_Object*)FOREIGN_string_utf_16);
5395 scheme_addto_prim_instance("_string/utf-16", (Scheme_Object*)t, env);
5396 s = scheme_intern_symbol("bytes");
5397 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5398 t->so.type = ctype_tag;
5399 t->basetype = (s);
5400 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5401 t->c_to_scheme = ((Scheme_Object*)FOREIGN_bytes);
5402 scheme_addto_prim_instance("_bytes", (Scheme_Object*)t, env);
5403 s = scheme_intern_symbol("path");
5404 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5405 t->so.type = ctype_tag;
5406 t->basetype = (s);
5407 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5408 t->c_to_scheme = ((Scheme_Object*)FOREIGN_path);
5409 scheme_addto_prim_instance("_path", (Scheme_Object*)t, env);
5410 s = scheme_intern_symbol("symbol");
5411 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5412 t->so.type = ctype_tag;
5413 t->basetype = (s);
5414 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_pointer));
5415 t->c_to_scheme = ((Scheme_Object*)FOREIGN_symbol);
5416 scheme_addto_prim_instance("_symbol", (Scheme_Object*)t, env);
5417 s = scheme_intern_symbol("pointer");
5418 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5419 t->so.type = ctype_tag;
5420 t->basetype = (s);
5421 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_pointer));
5422 t->c_to_scheme = ((Scheme_Object*)FOREIGN_pointer);
5423 REGISTER_SO(scheme_pointer_ctype);
5424 scheme_pointer_ctype = (Scheme_Object *)t;
5425 scheme_addto_prim_instance("_pointer", (Scheme_Object*)t, env);
5426 s = scheme_intern_symbol("gcpointer");
5427 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5428 t->so.type = ctype_tag;
5429 t->basetype = (s);
5430 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5431 t->c_to_scheme = ((Scheme_Object*)FOREIGN_gcpointer);
5432 scheme_addto_prim_instance("_gcpointer", (Scheme_Object*)t, env);
5433 s = scheme_intern_symbol("scheme");
5434 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5435 t->so.type = ctype_tag;
5436 t->basetype = (s);
5437 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_gcpointer));
5438 t->c_to_scheme = ((Scheme_Object*)FOREIGN_scheme);
5439 scheme_addto_prim_instance("_scheme", (Scheme_Object*)t, env);
5440 s = scheme_intern_symbol("fpointer");
5441 t = (ctype_struct*)scheme_malloc_tagged(sizeof(ctype_struct));
5442 t->so.type = ctype_tag;
5443 t->basetype = (s);
5444 t->scheme_to_c = ((Scheme_Object*)(void*)(&ffi_type_pointer));
5445 t->c_to_scheme = ((Scheme_Object*)FOREIGN_fpointer);
5446 scheme_addto_prim_instance("_fpointer", (Scheme_Object*)t, env);
5447 scheme_addto_prim_instance("prop:cpointer", scheme_cpointer_property, env);
5448 scheme_restore_prim_instance(env);
5449 }
5450
5451 /*****************************************************************************/
5452
5453 #else /* DONT_USE_FOREIGN */
5454
scheme_is_cpointer(Scheme_Object * cp)5455 int scheme_is_cpointer(Scheme_Object *cp)
5456 {
5457 return (SCHEME_FALSEP(cp)
5458 || SCHEME_CPTRP(x)
5459 || SCHEME_BYTE_STRINGP(x)
5460 || (SCHEME_CHAPERONE_STRUCTP(cp)
5461 && scheme_struct_type_property_ref(scheme_cpointer_property, cp)));
5462 }
5463
unimplemented(int argc,Scheme_Object ** argv,Scheme_Object * who)5464 static Scheme_Object *unimplemented(int argc, Scheme_Object **argv, Scheme_Object *who)
5465 {
5466 scheme_signal_error("%s: foreign interface not supported for this platform",
5467 ((Scheme_Primitive_Proc *)who)->name);
5468 return NULL;
5469 }
5470
foreign_compiler_sizeof(int argc,Scheme_Object ** argv)5471 static Scheme_Object *foreign_compiler_sizeof(int argc, Scheme_Object **argv)
5472 {
5473 return scheme_make_integer(4);
5474 }
5475
foreign_make_ctype(int argc,Scheme_Object ** argv)5476 static Scheme_Object *foreign_make_ctype(int argc, Scheme_Object **argv)
5477 {
5478 return scheme_false;
5479 }
5480
foreign_make_late_will_executor(int argc,Scheme_Object * argv[])5481 static Scheme_Object *foreign_make_late_will_executor(int argc, Scheme_Object *argv[])
5482 {
5483 return scheme_make_late_will_executor();
5484 }
5485
scheme_init_foreign(Scheme_Env * env)5486 void scheme_init_foreign(Scheme_Env *env)
5487 {
5488 /* Create a dummy module. */
5489 scheme_switch_prim_instance(env, "#%foreign");
5490 scheme_addto_primitive_instance("ffi-lib?",
5491 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-lib?", 1, 1), env);
5492 scheme_addto_primitive_instance("ffi-lib",
5493 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-lib", 1, 3), env);
5494 scheme_addto_primitive_instance("ffi-lib-name",
5495 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-lib-name", 1, 1), env);
5496 scheme_addto_primitive_instance("ffi-lib-unload",
5497 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-lib-unload", 1, 1), env);
5498 scheme_addto_primitive_instance("ffi-obj?",
5499 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-obj?", 1, 1), env);
5500 scheme_addto_primitive_instance("ffi-obj",
5501 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-obj", 2, 2), env);
5502 scheme_addto_primitive_instance("ffi-obj-lib",
5503 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-obj-lib", 1, 1), env);
5504 scheme_addto_primitive_instance("ffi-obj-name",
5505 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-obj-name", 1, 1), env);
5506 scheme_addto_primitive_instance("ctype?",
5507 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype?", 1, 1), env);
5508 scheme_addto_primitive_instance("ctype-basetype",
5509 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-basetype", 1, 1), env);
5510 scheme_addto_primitive_instance("ctype-scheme->c",
5511 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-scheme->c", 1, 1), env);
5512 scheme_addto_primitive_instance("ctype-c->scheme",
5513 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-c->scheme", 1, 1), env);
5514 scheme_addto_primitive_instance("make-ctype",
5515 scheme_make_noncm_prim((Scheme_Prim *)foreign_make_ctype, "make-ctype", 3, 3), env);
5516 scheme_addto_primitive_instance("make-cstruct-type",
5517 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-cstruct-type", 1, 4), env);
5518 scheme_addto_primitive_instance("make-array-type",
5519 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-array-type", 2, 2), env);
5520 scheme_addto_primitive_instance("make-union-type",
5521 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-union-type", 1, -1), env);
5522 scheme_addto_primitive_instance("ffi-callback?",
5523 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ffi-callback?", 1, 1), env);
5524 scheme_addto_primitive_instance("cpointer?",
5525 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "cpointer?", 1, 1), env);
5526 scheme_addto_primitive_instance("cpointer-tag",
5527 scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "cpointer-tag", 1, 1), env);
5528 scheme_addto_primitive_instance("set-cpointer-tag!",
5529 scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "set-cpointer-tag!", 2, 2), env);
5530 scheme_addto_primitive_instance("cpointer-gcable?",
5531 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "cpointer-gcable?", 1, 1), env);
5532 scheme_addto_primitive_instance("ctype-sizeof",
5533 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-sizeof", 1, 1), env);
5534 scheme_addto_primitive_instance("ctype-alignof",
5535 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "ctype-alignof", 1, 1), env);
5536 scheme_addto_primitive_instance("compiler-sizeof",
5537 scheme_make_immed_prim((Scheme_Prim *)foreign_compiler_sizeof, "compiler-sizeof", 1, 1), env);
5538 scheme_addto_primitive_instance("malloc",
5539 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "malloc", 1, 5), env);
5540 scheme_addto_primitive_instance("end-stubborn-change",
5541 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "end-stubborn-change", 1, 1), env);
5542 scheme_addto_primitive_instance("free",
5543 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "free", 1, 1), env);
5544 scheme_addto_primitive_instance("malloc-immobile-cell",
5545 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "malloc-immobile-cell", 1, 1), env);
5546 scheme_addto_primitive_instance("free-immobile-cell",
5547 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "free-immobile-cell", 1, 1), env);
5548 scheme_addto_primitive_instance("ptr-add",
5549 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-add", 2, 3), env);
5550 scheme_addto_primitive_instance("ptr-add!",
5551 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-add!", 2, 3), env);
5552 scheme_addto_primitive_instance("offset-ptr?",
5553 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "offset-ptr?", 1, 1), env);
5554 scheme_addto_primitive_instance("ptr-offset",
5555 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-offset", 1, 1), env);
5556 scheme_addto_primitive_instance("set-ptr-offset!",
5557 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "set-ptr-offset!", 2, 3), env);
5558 scheme_addto_primitive_instance("vector->cpointer",
5559 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "vector->cpointer", 1, 1), env);
5560 scheme_addto_primitive_instance("flvector->cpointer",
5561 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "flvector->cpointer", 1, 1), env);
5562 scheme_addto_primitive_instance("extflvector->cpointer",
5563 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "extflvector->cpointer", 1, 1), env);
5564 scheme_addto_primitive_instance("memset",
5565 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "memset", 3, 5), env);
5566 scheme_addto_primitive_instance("memmove",
5567 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "memmove", 3, 6), env);
5568 scheme_addto_primitive_instance("memcpy",
5569 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "memcpy", 3, 6), env);
5570 scheme_addto_primitive_instance("ptr-ref",
5571 scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "ptr-ref", 2, 4), env);
5572 scheme_addto_primitive_instance("ptr-set!",
5573 scheme_make_inline_noncm_prim((Scheme_Prim *)unimplemented, "ptr-set!", 3, 5), env);
5574 scheme_addto_primitive_instance("ptr-equal?",
5575 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ptr-equal?", 2, 2), env);
5576 scheme_addto_primitive_instance("make-sized-byte-string",
5577 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "make-sized-byte-string", 2, 2), env);
5578 scheme_addto_primitive_instance("ffi-call",
5579 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-call", 3, 10), env);
5580 scheme_addto_primitive_instance("ffi-call-maker",
5581 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-call-maker", 2, 9), env);
5582 scheme_addto_primitive_instance("ffi-callback",
5583 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-callback", 3, 6), env);
5584 scheme_addto_primitive_instance("ffi-callback-maker",
5585 scheme_make_noncm_prim((Scheme_Prim *)unimplemented, "ffi-callback-maker", 2, 6), env);
5586 scheme_addto_primitive_instance("saved-errno",
5587 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "saved-errno", 0, 1), env);
5588 scheme_addto_primitive_instance("lookup-errno",
5589 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "lookup-errno", 1, 1), env);
5590 scheme_addto_primitive_instance("make-late-will-executor",
5591 scheme_make_immed_prim((Scheme_Prim *)foreign_make_late_will_executor, "make-late-will-executor", 0, 0), env);
5592 scheme_addto_primitive_instance("make-late-weak-box",
5593 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "make-late-weak-box", 1, 1), env);
5594 scheme_addto_primitive_instance("make-late-weak-hasheq",
5595 scheme_make_immed_prim((Scheme_Prim *)unimplemented, "make-late-weak-hasheq", 0, 0), env);
5596 scheme_add_global_constant("_void", scheme_false, env);
5597 scheme_add_global_constant("_int8", scheme_false, env);
5598 scheme_add_global_constant("_uint8", scheme_false, env);
5599 scheme_add_global_constant("_int16", scheme_false, env);
5600 scheme_add_global_constant("_uint16", scheme_false, env);
5601 scheme_add_global_constant("_int32", scheme_false, env);
5602 scheme_add_global_constant("_uint32", scheme_false, env);
5603 scheme_add_global_constant("_int64", scheme_false, env);
5604 scheme_add_global_constant("_uint64", scheme_false, env);
5605 scheme_add_global_constant("_fixint", scheme_false, env);
5606 scheme_add_global_constant("_ufixint", scheme_false, env);
5607 scheme_add_global_constant("_fixnum", scheme_false, env);
5608 scheme_add_global_constant("_ufixnum", scheme_false, env);
5609 scheme_add_global_constant("_float", scheme_false, env);
5610 scheme_add_global_constant("_double", scheme_false, env);
5611 scheme_add_global_constant("_longdouble", scheme_false, env);
5612 scheme_add_global_constant("_double*", scheme_false, env);
5613 scheme_add_global_constant("_bool", scheme_false, env);
5614 scheme_add_global_constant("_stdbool", scheme_false, env);
5615 scheme_add_global_constant("_string/ucs-4", scheme_false, env);
5616 scheme_add_global_constant("_string/utf-16", scheme_false, env);
5617 scheme_add_global_constant("_bytes", scheme_false, env);
5618 scheme_add_global_constant("_path", scheme_false, env);
5619 scheme_add_global_constant("_symbol", scheme_false, env);
5620 scheme_add_global_constant("_pointer", scheme_false, env);
5621 scheme_add_global_constant("_gcpointer", scheme_false, env);
5622 scheme_add_global_constant("_scheme", scheme_false, env);
5623 scheme_add_global_constant("_fpointer", scheme_false, env);
5624 scheme_addto_primitive_instance("prop:cpointer", scheme_cpointer_property, env);
5625 scheme_restore_prim_instance(env);
5626 }
5627
5628 #endif
5629