[Haskell-cafe] Mixing C++ and Haskell, OpenSSL thread safety, and using mmap

Branimir Maksimovic bmaxa at hotmail.com
Thu Dec 8 02:06:12 EST 2005


I wrotted some messages on fa.haskell newsgroup but then I've figured that 
people
actually read mailing lists :)
So this is digest of mine recent messages on this newsgroup.

First I want to say about OpenSSL thread safety. It is not thread safe by 
default.
Who wants to import and use OpenSLL functions with FFI, have to set locking 
hooks for it,
or else spurious  crashes with useless stack trace will result. Higher level 
of concurrency,
more likely crash will happen.
Since this hooks are called by C, it is easer to setup mutexes in C module, 
then call Haskell
main function from it.
details:
http://www.openssl.org/docs/crypto/threads.html

Second I've successfully linked Haskell and C++ with threaded run time.
Well, I'm planning to use Haskell in C++ programs and to call
Haskell functions from C++ and vice versa.
So far I've tried some small test programs and it seems works ok.
If I launch threads from C++ then call Haskell I have to
link with -threaded flag as Haskell run time complains about
entering functions unsafelly without it.
Also I have another question about hs_add_root.
Is this neccessary? I've tried with and without call to
this function and everything seems to work same way.
That means I don't notice any difference. I ask this because
if for example I have lot of Haskell modules do I need to call
hs_add_root for every and each one?
This is just a small example that works both on linux and windows,
(I have different C++ versions but Haskell module is same).
Haskell makes and frees array of pointers to CStrings (char**)
from argument that is CString(char*). Error checking and handling
is intentionally left out for now.
I would appreciate any critics about it, as I've started
to learn language one month ago, but have professional experience since 92
in other languages, specially C++.

-- Haskell module
module MakeWords where
import Foreign
import Foreign.C.String
import Foreign.Storable
import Foreign.Ptr
import Foreign.Marshal.Array
foreign export ccall makeWords :: CString -> IO (Ptr CString)
foreign export ccall freeWords :: Ptr CString -> IO ()

makeWords :: CString -> IO (Ptr CString)
makeWords cs = do let lst = words $ unsafePerformIO $ peekCString cs
                            p <-  mallocArray0 $ length lst
                            makeWords' lst p
                            return (p)

makeWords' :: [String] -> Ptr CString -> IO ()
makeWords' [] p = do poke p nullPtr
makeWords' (s:strs) p = do poke p $ unsafePerformIO $ newCString s
                                      makeWords' strs (plusPtr p $ sizeOf p)


freeWords :: Ptr CString -> IO ()
freeWords p = do freeWords' p
                          free p

freeWords' :: Ptr CString -> IO ()
freeWords' p = if nullPtr /= (unsafePerformIO $ peek p)
                        then do free $ unsafePerformIO $ peek p
                                    freeWords' $ plusPtr p $ sizeOf p
                        else return ()
-- end Haskell module

// C++, windows version
#include <HsFFI.h>
#ifdef __GLASGOW_HASKELL__
#include "makeWords_stub.h"
#endif
#include <iostream>
#include <ostream>
#include <windows.h>
using namespace std;

class Mutex{
public:
Mutex(){ InitializeCriticalSection(&s); }
~Mutex(){ DeleteCriticalSection(&s); }
void acquire(){ EnterCriticalSection(&s); }
void release(){ LeaveCriticalSection(&s); }
private:
Mutex(const Mutex&);
Mutex& operator=(const Mutex&);
CRITICAL_SECTION s;
}m;

DWORD WINAPI tf(LPVOID arg)
{
for(int i=0;i<100000;++i)
{
   const char** p = (const char**)makeWords(arg?arg:(void*)"boring 
default");
   const char** q = p;
   if(!(i%10000))
   {
    m.acquire();
    while(*q){ cout<<*q++<<' '; }
    cout<<endl;
    m.release();
   }
   freeWords(p);
}
return 0;
}

#ifdef __GLASGOW_HASKELL__
extern "C" void __stginit_MakeWords();
#endif

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int main(int argc,char* argv[])
{
  hs_init(&argc,&argv);

#if defined(__GLASGOW_HASKELL__) && defined(STGINIT_NEDEED)
  hs_add_root(__stginit_MakeWords); // is this neccessary?
                                    // seems works without it,
                                    // both on linux and windows
#endif

  DWORD t[NUM_THREADS];
  HANDLE h[NUM_THREADS];
  char *args[NUM_THREADS] = { "abc def",
                              "one two three",
                              "house on the beach",
                              "end of the line",
                            };
  for(int i =0; i<NUM_THREADS;++i)
  {
   h[i]=CreateThread(NULL,0,tf,args[i],0,&t[i]);
  }
  DWORD waitall = WaitForMultipleObjects(NUM_THREADS,h,TRUE,INFINITE);
  for(int i =0; i<NUM_THREADS;++i)
    CloseHandle(h[i]);
  hs_exit();
}
// end C++

If someone is interested, it is possible to use g++ to link but -u flag 
symbols have to be
obtained by -v3 flag to ghc first.

Third, can I use mmap in Haskell? I see that there is MArray whitch is base 
for
StorableArray, but I need MMappedArray which will use mmap on linux or 
CreateFileMapping
and MapViewOfFile on windows instead of malloc. So I would appreciate if 
someone
knows if there is such class already, but it isn;t a problem to reuse 
StorableArray code
and create new persistent Array based on this.


Greetings, Bane.

_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE! 
http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/



More information about the Haskell-Cafe mailing list