不能让C2HS与“外国”指针一起工作

时间:2012-08-22 10:06:50

标签: haskell ffi c2hs

一般信息

我目前正在试验Haskell的C-> Haskell(C2HS)接口生成器。在第一个glace,它真棒,我在几个小时内连接了一个相当复杂的C ++库(使用一个小的extern C - 包装器)。 (我之前从未做过任何FFI。)

只有一个问题:如何释放在C / C ++库中分配的内存?我在C2HS documentation中找到{#pointer ... foreign #},看起来就像我追求的那样。由于我的C-wrapper将C ++库转换为具有参考透明度和功能接口的库,Haskell Storage Manager应该能够为我做好工作:-)。不幸的是,我无法让这个工作。为了更好地解释我的问题,我设置了一个小的demo project on GitHub,它具有与C / C ++库+包装器相同的属性,但没有开销。如您所见,该库与pure unsafe FFI一起使用是完全安全的。

演示项目

在GitHub上,我创建了一个small demo project,其组织如下:

C库

C库非常简单且无用:您可以传递一个整数,并且可以从库中获取尽可能多的整数(当前为[0..n])。记住:图书馆没用,只是一个演示。接口也非常简单:函数LTIData lti_new_data(int n)将(在传递整数之后)返回某种包含C库的已分配数据的不透明对象。该库还有两个访问函数int lti_element_count(LTIData data)int lti_get_element(LTIData data, int n),前者将返回元素数,后者将返回元素n。啊,最后但并非最不重要的是,图书馆的用户在使用它之后应该使用LTIData释放不透明的void lti_free_data(LTIData data)

低级Haskell绑定

使用C2HS设置低级Haskell绑定,您可以在

中找到它

高级Haskell API

为了好玩,我还使用低级API绑定和使用高级API的high-level Haskell API设置了simple driver program种。使用驱动程序和例如valgrind可以很容易地看到泄漏的内存(对于每个参数p_1, p_2, ..., p_n,库执行\sum_{i = 1..n} 1 + p_i分配;可以很容易地观察到如下内容:

$ valgrind dist/build/TestHsLTI/TestHsLTI 100             2>&1 | grep -e allocs -e frees
==22647==   total heap usage: 184 allocs, 74 frees, 148,119 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100         2>&1 | grep -e allocs -e frees
==22651==   total heap usage: 292 allocs, 80 frees, 181,799 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100 100     2>&1 | grep -e allocs -e frees
==22655==   total heap usage: 400 allocs, 86 frees, 215,479 bytes allocated

$ valgrind dist/build/TestHsLTI/TestHsLTI 100 100 100 100 2>&1 | grep -e allocs -e frees
==22659==   total heap usage: 508 allocs, 92 frees, 249,159 bytes allocated

演示的当前状态

只需输入git clone https://github.com/weissi/c2hs-experiments.git && cd c2hs-experiments && cabal configure && cabal build && dist/build/TestHsLTI/TestHsLTI

,您就可以克隆,编译和运行project

那又是什么问题?

问题是该项目仅使用Foreign.Ptr而不是使用C2HS的Foreign.ForeignPtr的“托管”版本{#pointer ... foreign #},我无法使其工作。在演示项目中,我还添加了一个.chs file trying to use these foreign pointers,但它不起作用:-(。我努力尝试但是没有任何成功。

还有一件事我也不明白:如何告诉GHC使用C2HS如何释放图书馆的数据。演示项目的库提供了一个函数void lti_free_data(LTIData data),应该调用该函数来释放内存。但是GHC猜不出来了!?!如果GHC使用常规free(),则不会释放所有内存: - (。

1 个答案:

答案 0 :(得分:3)

问题解决了:我在互联网上找到this file doing something similar并且能够解决它: - )。

它需要的是一些样板编组码:

foreign import ccall "lib_to_interface.h &lti_free_data"
  ltiFreeDataPtr :: FunPtr (Ptr (LTIDataHs) -> IO ())


newObjectHandle :: Ptr LTIDataHs -> IO LTIDataHs
newObjectHandle p = do
  fp <- newForeignPtr ltiFreeDataPtr p
  return $ LTIDataHs fp

这是final managed (ForeignPtr) verion of the .chs file