Hello All,
I'm trying to write a PCRE FFI for Gambit Version 4.0 beta 17. One of my C functions, c_wrap_pcre_match_ovector, is meant to convert the offset vector from a PCRE match (simply an array of integers) into a scheme vector. This function is attached at the end of this email as well as a crash report.
The code works fine if everything is compiled and run like this:
gsc pcre.scm gcc pcre*.c -lpcre -lgambc ./a.out
But when I try to compile it as a loadable library, my programs crash as soon as ___make_vector is called from c_wrap_pcre_match_ovector. This is how I'm trying to compile and use the library:
gsc -o pcre.o1.c -flat pcre > /dev/null gcc -o pcre.o1 -bundle -D___DYNAMIC -lpcre pcre-wrapper.c pcre.c pcre.o1.c gsi pcre.o1 pcre-test.scm
My source files are:
pcre.scm The FFI wrappers pcre-wrapper.c Some wrapper functions, including c_wrap_pcre_match_ovector pcre-wrapper.h Declarations for pcre-wrapper.c pcre-test.scm Some test calls to pcre-match, etc.
I'm using gcc 4.0.1 on Mac OS X 10.4.8 (PowerPC).
Any help is appreciated. On a related note, is there a benefit to constructing a vector like this in C-space versus making a c-lambda to grab an entry from the int[] and constructing the vector in scheme-space instead? I considered both options, but my rational for constructing the vector in C-space is to minimize the number of FFI calls needed to process a match.
Thanks,
-Ben
=================================================================
___SCMOBJ c_wrap_pcre_match_ovector(c_wrap_pcre_match *match) { ___SCMOBJ ___err = ___FIX(___NO_ERR); ___SCMOBJ result; ___SCMOBJ offset; ___SCMOBJ length; int i, limit;
if ((match == NULL) || ((limit = match->rc) < 0)) { return ___FAL; }
if (limit == 0) { /* * ovector wasn't big enough, the first 2/3 are used * and the rest of the matches were discarded */ limit = match->ovecsize / 3; }
/* convert the ovector to a scheme vector */ limit = 2 * limit;
/* CRASH happens at the line below */ result = ___EXT(___make_vector)(limit, ___FAL, ___STILL);
if (___FIXNUMP(result)) { return result; }
for (i = 0; (i < limit) && (___err == ___FIX(___NO_ERR)); i++) { ___BEGIN_SFUN_INT_TO_SCMOBJ(match->ovector[i], offset, 1) ___FIELD(result, i) = offset; ___END_SFUN_INT_TO_SCMOBJ(match->ovector[i], offset, 1) }
___EXT(___release_scmobj)(result);
if (___err != ___FIX(___NO_ERR)) { return ___err; }
return result; }
=================================================================
Date/Time: 2006-10-19 22:06:37.043 -0400 OS Version: 10.4.8 (Build 8L127) Report Version: 4
Command: gsi Path: /usr/local/bin/gsi Parent: zsh [25726]
Version: ??? (???)
PID: 27331 Thread: 0
Exception: EXC_BAD_ACCESS (0x0001) Codes: KERN_PROTECTION_FAILURE (0x0002) at 0x0000040c
Thread 0 Crashed: 0 pcre.o1 0x003e34e8 c_wrap_pcre_match_ovector + 156 (bundle1.s:283) 1 pcre.o1 0x003e5244 ___H__20_pcre_23_5 + 412 (bundle1.s:283) 2 gsi 0x001bb338 ___call + 376 (crt.c:355) 3 gsi 0x001bc2bc ___setup + 3204 (crt.c:355) 4 gsi 0x001b6390 ___main + 2464 (crt.c:355) 5 gsi 0x000048e8 ___main_char + 132 (crt.c:355) 6 gsi 0x000047f4 main + 40 (crt.c:355) 7 gsi 0x00001e30 _start + 344 (crt.c:272) 8 gsi 0x00001cd4 start + 60
Binary Images Description: 0x1000 - 0x1d7fff gsi /usr/local/bin/gsi 0x3e2000 - 0x3f6fff pcre.o1 /Users/bweaver/work/weaver@coptix.com/pcre/pcre.o1 0x505000 - 0x514fff libpcre.0.dylib /usr/local/lib/libpcre.0.dylib 0x8fe00000 - 0x8fe51fff dyld 45.3 /usr/lib/dyld 0x90000000 - 0x901bcfff libSystem.B.dylib /usr/lib/libSystem.B.dylib 0x90214000 - 0x90219fff libmathCommon.A.dylib /usr/lib/system/libmathCommon.A.dylib 0x94be3000 - 0x94c03fff libmx.A.dylib /usr/lib/libmx.A.dylib
Model: PowerBook6,2, BootROM 4.7.5f1, 1 processors, PowerPC G4 (1.1), 1 GHz, 768 MB Graphics: GeForce FX Go5200 32MB, GeForce FX Go5200 32MB, AGP, 32 MB Memory Module: DIMM0/BUILT-IN, 256 MB, built-in, built-in Memory Module: DIMM1/J31, 512 MB, DDR SDRAM, PC2700U-25330 AirPort: AirPort Extreme, 405.1 (3.90.34.0.p18) Modem: MicroDash, UCJ, V.92, 1.0F, APPLE VERSION 2.6.6 Bluetooth: Version 1.7.8f2, 2 service, 0 devices, 1 incoming serial ports Network Service: Built-in Ethernet, Ethernet, en0 Parallel ATA Device: MATSHITACD-RW CW-8123, Parallel ATA Device: TOSHIBA MK6025GAS, 55.89 GB USB Device: Hub in Apple Pro Keyboard, Mitsumi Electric, Up to 12 Mb/sec, 500 mA USB Device: Microsoft IntelliMouse. Explorer, Microsoft, Up to 1.5 Mb/sec, 100 mA USB Device: Apple Pro Keyboard, Mitsumi Electric, Up to 12 Mb/sec, 250 mA USB Device: Bluetooth HCI, , Up to 12 Mb/sec, 500 mA
Afficher les réponses par date
At 21:32 Uhr -0500 19.10.2006, Ben Weaver wrote:
Any help is appreciated.
I don't know the problem of your ___make_vector invocation. But:
On a related note, is there a benefit to constructing a vector like this in C-space versus making a c-lambda to grab an entry from the int[] and constructing the vector in scheme-space instead? I considered both options, but my rational for constructing the vector in C-space is to minimize the number of FFI calls needed to process a match.
There is the ##c-code special form with which you can embedd C code directly into scheme, and which has no overhead at all. But note that I've grabbed this from reading the Gambit sources, I don't know whether Marc thinks it's a good idea if users are making use of this.
You can represent C pointers as scheme fixnums if they are aligned to word boundaries (the fixnum is then representing the *word* index, not byte index), so there's no conversion overhead (but you loose type checking by the C compiler, of course). For example:
(define (mem-addressword obj) ;; returns a fixnum, which may be negative. (##c-code "___RESULT= ___MEM_ALLOCATED(___ARG1) ? (___ARG1 &~ ___CAST(___WORD,3)) /* creates a fixnum */ : ___FAL;" obj))
So something like this may be better to work with (untested!):
(c-define "#define WORDADDRESS_AS(x,cast) ((cast)(___INT(x)*___WS))")
(define (match:rc match-addressword) (##c-code "___RESULT= ___FIX(WORDADDRESS_AS(___ARG1, c_wrap_pcre_match *)->rc);" ;; assumes that rc is in fixnum range! match-addressword))
(define (match:ovecsize match-addressword) (##c-code "___RESULT= ___FIX(WORDADDRESS_AS(___ARG1, c_wrap_pcre_match *)->ovecsize);" ;; dito match-addressword))
;;( one could generate the above (and more) accessors through a macro )
(define (wrap-pcre-match-ovector match) ;; match is an adressword fixnum (and (= match-addressword 0) ;; could also use ##fixnum.= (let ((limit (match:rc match))) (and (>= limit 0) (let* ((limit (* 2 (if (= limit 0) (/ (match:ovecsize match) 3) limit))) (vec (##make-vector limit))) (let lp ((i 0)) (if (< i limit) (begin (vector-set! vec i (##c-code "___RESULT= ___FIX(WORDADDRESS_AS(___ARG1, c_wrap_pcre_match *)->ovector[___INT(___ARG2)];" match i)) (lp (+ i 1))))) vec)))))
If the integer values are not guaranteed to be within fixnum range, either use a c-lambda for the conversion (maybe Marc could look into making c-lambda faster in such cases?), or use your code (maybe the whole C for loop) inside ##c-code. Or use u32- or s32vectors (or the 64bit counterparts if necessary, choosing the right ones (at compilation (difficult?)) or init time by checking the size of the integer type).
It may be easier to work this way since you can play interactively with the C parts from the repl. And Gambit will allocate small vectors as movable objects this way, which can be up to about 3 times faster than using still objects. OTOH, by using the fixnum pointer representation you're playing unsafe (you could instead use foreign pointer objects (during development and switch to fixnums at the end)).
Christian.
PS. if you're using u32/s32/u64/s64 vectors, you could just use memcpy to transfer the values.