我正在尝试使用MIT-SHM 扩展的绑定来扩展OCaml-Xlib。这是我第一次尝试将 C 与 OCaml 连接,而且我从来没有用 C 写过任何东西,所以我想我在某处做了一些愚蠢的事情。
我首先添加了 XShmQueryExtension 函数。我将以下内容添加到 Xlib.ml 文件中
external xShmQueryExtension: dpy:display -> bool = "ml_xShmQueryExtension"
wrap_xlib.c 文件的以下内容
CAMLprim value
ml_xShmQueryExtension( value dpy )
{
int ans = XShmQueryExtension( Display_val(dpy) );
return Val_bool(ans);
}
我将 Makefile 更改为与 Xext 链接,它可以工作:当我从 OCaml 调用 xShmQueryExtension 函数时,我得到了正确的结果。
现在我正在尝试编写一个创建共享 xImage 的函数,初始化共享内存并将其附加到 X 服务器。我在 Xlib.ml 文件中添加了以下内容:
type xShmSegmentInfo
external xShmCreateImageAndAttach:
dpy:display -> visual:visual -> depth:int -> fmt:ximage_format
-> width:uint -> height:uint -> xShmSegmentInfo * xImage
= "ml_xShmCreateImageAndAttach_bytecode"
"ml_xShmCreateImageAndAttach"
以及 wrap_xlib.c 文件的以下内容:
#define Val_XShmSegmentInfo(d) ((value)(d))
#define XShmSegmentInfo_val(v) ((XShmSegmentInfo *)(v))
CAMLprim value
ml_xShmCreateImageAndAttach( value dpy, value visual, value depth, value format,
value width, value height)
{
CAMLparam5(dpy, visual, depth, format, width);
CAMLxparam1(height);
CAMLlocal1(ret);
XShmSegmentInfo *shminfo = malloc(sizeof(XShmSegmentInfo));
XImage *ximage = XShmCreateImage(
Display_val(dpy),
Visual_val(visual),
Int_val(depth),
XImage_format_val(format),
NULL,
shminfo,
UInt_val(width),
UInt_val(height)
);
shminfo->shmid = shmget (IPC_PRIVATE,
ximage->bytes_per_line * ximage->height, IPC_CREAT|0777);
shminfo->shmaddr = ximage->data = (char *) shmat (shminfo->shmid, 0, 0);
if (shminfo->shmaddr == -1)
fprintf(stderr,"Error");
shminfo->readOnly = False;
XShmAttach (Display_val(dpy), shminfo);
ret = caml_alloc(2, 0);
Store_field(ret, 0, Val_XShmSegmentInfo(shminfo) );
Store_field(ret, 1, Val_XImage(ximage) );
CAMLreturn(ret);
}
CAMLprim value
ml_xShmCreateImageAndAttach_bytecode( value * argv, int argn )
{
return ml_xShmCreateImageAndAttach(argv[0], argv[1], argv[2], argv[3],
argv[4], argv[5]);
}
现在我在我的 OCaml 程序中调用这个函数:
let disp = xOpenDisplay ""
let screen = xDefaultScreen disp
let (shminfo, image) = xShmCreateImageAndAttach disp
(xDefaultVisual disp screen)
(xDefaultDepth disp screen) ZPixmap 640 174
这是我的 OCaml 程序中的顶级调用,我再也不会使用变量 shminfo 和 image (这只是为了测试该函数是否有效)。这个调用没有失败,但我的程序段错误一段时间后(我的程序的其余部分不断用 xGetImage 转储屏幕并用像素做一些事情,我在一些 xGetPixel 中得到一个段错误,这与调用无关xShmCreateImageAndAttach 上面)。我注意到,如果我删除该行,shminfo->shmaddr = ximage->data = (char *) shmat (shminfo->shmid, 0, 0);
我就不会再出现段错误(但这当然不会做我想要的)。
我认为这与垃圾收集器有关,但我不知道如何解决。在OCaml doc上,有一条关于将使用 malloc 获得的指针转换为值类型的警告,但我不太明白它的含义,也不知道它是否相关。
编辑:
我将以下两行替换为shmat
以下内容:
fprintf(stderr,"%i\n",(int)shminfo->shmaddr);
fflush(stderr);
我得到类似的东西1009700864
,所以调用shmat
似乎正在工作。
这是gdb给出的回溯:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7acdde8 in ?? () from /usr/lib/libX11.so.6
(gdb) backtrace
#0 0x00007ffff7acdde8 in ?? () from /usr/lib/libX11.so.6
#1 0x000000000044070c in ml_XGetPixel ()
#2 0x00000000004165b9 in camlInit__rvb_at_1023 () at init.ml:43
#3 0x0000000000415743 in camlParse__find_guy_1046 () at parse.ml:58
#4 0x000000000041610c in camlParse__pre_parse_1044 () at parse.ml:95
#5 0x0000000000415565 in camlGame__entry () at game.ml:26
#6 0x00000000004141f9 in caml_program ()
#7 0x000000000045c03e in caml_start_program ()
#8 0x000000000044afa5 in caml_main ()
#9 0x000000000044afe0 in main ()