Thursday, June 5, 2014

Haskell FFI Example

There are a few examples and tutorials that are out there on the Foreign Function Interface (FFI) in Haskell but I personally feel that you can never have too many examples. This past week I was working on calling C functions from Haskell, and this post will walk through a few examples and will hopefully warn you of some pitfalls that I ran into.

Why Use FFI? 

Here are a few reasons why you would want to use FFI:
  • You are looking for a library to solve a particular problem and you can't find any packages in your current language that would solve it well, but you find a tested library in a different language.
  • The implementation of a library in your current language is inefficient when compared with another language's implementation
  •  You really love a particular language and have to use it in any project that you touch because let's face it, that language is awesome
  • You want to learn a FFI...
I haven't played around with calling Haskell from C much so I'll leave that part for another day. Without further ado, here is an example of using Haskell to call C functions:

Example Background 

I was working on a project that used Xen's Hypervisor. Within Xen there is a communication mechanism called XenVChan that allows communication between two virtual machines on the same hypervisor. The implementation of this mechanism is all in C. With the communication we chose to use Haskell in order to give us the ability to have typed packets in our communication as well as all the other fun things Haskell can do. After glancing through the C source code I quickly realized that we were not going to want to re-implement VChan in Haskell. That leads us to using FFI. 

Here is an example of a C function that I would like to call from Haskell:

int readClientMessage(xentoollog_logger * xc_logger, struct libxenvchan * ctrl,
                        char * msg, int * sz);

We have a few things to figure out:
  1. How do we call a C function from Haskell? - Our original general question
  2. How can we create variables in Haskell that have types that C will accept when calling the function? 
  3. How do we deal with pointers?

Baby Steps - Calling a function in C from Haskell

Let's work on a more trivial C function first:

# Functions.c
int add( int x, int y);

This function simply adds x and y together and returns the result. To set up plumbing between Haskell and C Here's what we do:

#Haskell_Functions.hs
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import ccall unsafe "functions.h add" c_add :: CInt -> CInt -> CInt

We just created a new haskell function call c_add that has the type signature CInt->CInt->CInt. Here is what the syntax is:
foreign import ccall  [safe/unsafe] [HeaderFile funcName] [HaskellFunc]

safe - the C function may call back into the Haskell program before returning. This is basically a flag to tell Haskell that it needs to do the extra book-keeping necessary to accept a returning call from this function.
unsafe - the C function will not call back into the Haskell Program before returning

If unsafe/safe is not specified it will default to safe.

The next parameter is a string which specifies the location of the C Header file and the C function name that you are wanting to call. This can be an absolute path or a relative path ("../include/functions.h" would be valid).

The last parameter is the name and type signature of the function that your Haskell code will call. So in this example my Haskell code can call the C function by calling c_add.

Now to call c_add we just need to figure out how to make a CInt

C Types

By importing  Foreign.C.Types we can create a large number of C primitives, both signed and unsigned. The full list can be seen in the documentation: Foreign.C.Types.

In order to call c_add we need to create some CInt variables in haskell. we can do so in the following way:

fromIntegral 5 :: CInt 

My personal preference is to create another Haskell function that abstracts away all the marshalling needed between Haskell types and C types:

#Haskell_Functions.hs
myAdd x y = c_add (fromIntegral x :: CInt) (fromIntegral y :: CInt)

And that's it! A few other helpful functions:

fromRational  5.5 :: CDouble
castCharToCChar 'c'      -- == fromIntegral (ord 'c') :: CChar 
newCString "Hello World" -- String -> IO CString

Handling C Pointers in Haskell

Our original function needed an int * and a char * To allocate space for a CInt we have the following function:
alloca :: Storable a => (Ptr a -> IO b) -> IO b
Let's pretend that our C_add function takes a third parameter that is an int * to store the result: # Functions.c
 int add (int x, int y, int *res);

and that we did the corresponding  foreign setup calls: 

#Haskell_Functions.hs
foreign import ccall unsafe "functions.h add" c_addWithPtr :: CInt -> CInt-> Ptr CInt -> CInt

Here is how we would allocate the pointer and then look at the result

#Haskell_Functions.hs
myAddPtr :: Int -> Int -> IO Int
myAddPtr x y= alloca $ \ res -> do 
                          c_addWithPtr (fromIntegral x ::CInt) (fromIntegral y::CInt) res
                          return $ fromIntegral (peek res):: Int

We allocate a ptr called res we then call the function and afterwords we look at the result by calling peek to dereference the pointer and then return the Integer. If you needed to allocate more than one pointer then you would just nest the alloca calls.

Pointers to Data Structures

Let's look again at the opening C Function:
# Functions.h
int readClientMessage(xentoollog_logger * xc_logger, struct libxenvchan * ctrl,
                        char * msg, int * sz);
In this function we are passing around pointers to data structures instead of just pointers to primitives. In my case I never needed to look at the contents of the data structures I just needed a handle to pass these to different functions. I also had some functions that would return a pointer to the structure.  If you need to look at the values of the structures inside your Haskell program then I would recommend that you look at the "Working with C Structures" section here
If you don't need to look at the data structure in Haskell then I would recommend doing the following in your Haskell Code:
#Haskell_Functions.hs
{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-}

data XenToolLogger
data LibXenVChan


You can then pass around Ptr XenToolLogger and have then bound to a variable. Here are some functions that return pointers to data structures :

# Functions.c
xentoollog_logger * createDebugLogger(void);
struct libxenvchan * createReceiveChan (xentoollog_logger * xc_logger, int id);

The corresponding Haskell code to call these would be:

#Haskell_Functions.hs
foreign import ccall unsafe "../include/exp1Common.h createDebugLogger"
    c_createDebugLogger:: IO (Ptr XenToolLogger)

foreign import ccall unsafe "../include/exp1Common.h createReceiveChan"
    c_createReceiveChan:: Ptr XenToolLogger -> CInt-> IO (Ptr LibXenVChan)

createSrvCtrl :: Ptr XenToolLogger -> Int-> IO (Ptr LibXenVChan)
createSrvCtrl logger clientId = c_createreceivechan logger clientId

Now we just need to implement that initial function and we are done:

#Haskell_Functions.hs
foreign import ccall unsafe "../include/exp1Common.h readClientMessage"
    c_readClientMessage:: (Ptr XenToolLogger)->(Ptr LibXenVChan)-> CString -> Ptr CInt->IO (CInt)

readClientMessage :: (Ptr XenToolLogger)->(Ptr LibXenVChan)->Int->IO (Int)
readClientMessage logger chan dataSize = allocaArray0 dataSize $ \( ptr) ->
                    alloca $ \(size) -> do
                                    poke size (fromIntegral dataSize:: CInt)
                                    c_readClientMessage logger vchan ptr size
                                    sz<- peek size
                                    response <- peekCStringLen (ptr, fromIntegral sz:: Int)
                                    return $ response


There is a lot happening here and quite a few new things, let's walk through it:
  • We allocate an array using allocaArray0
    • allocaArray0 is just like alloca but it takes an Int as and allocates an array of that size +1 (the +1 is to make room for a \NUL character, if you don't want it use allocaArray instead)
  • We then allocate a pointer to a CInt
    • poke is a function that takes a pointer and a value and puts the value in the pointer
  • We then call our c function with the marshalled values and the string
  • Using peek we can dereference the pointers and look at the values
  • Using peekCStringLen we can look at the String  of a certain size
    • peekCStringLen will allow null characters in the string, if you want to get up until the null you can just use peekCString and it will give you everything until the first null character
  • We then return the value

Side Notes:

When calling the foreign import ccall  method and giving the Haskell type if the C function is pure you can give the Haskell a type that isn't IO (see the initial c_add function) but if it isn't a pure function you can include IO.

If a c function is asking for a char * as an argument you need to check about how it is used. If the function is allocating memory and then just setting your pointer to the front of it, then you can just do an alloca call instead of an allocaArray call.

I mentioned it in passing when talking about peekCStringLen, but don't forget that strings in C are nul terminated, whereas Haskell strings are not. This can lead to some "interesting" bugs if you are dealing with ByteStrings or other strings which have null characters in the string.




No comments:

Post a Comment