Re: opaque pointers and metatype

  • From: Richard Hundt <richardhundt@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Tue, 04 Mar 2014 01:23:13 +0100

On 3/4/14 12:18 AM, Cosmin Apreutesei wrote:
> A real example:
>
>    typedef struct pthread_mutex_t_* pthread_mutex_t;
>    int pthread_mutex_init (pthread_mutex_t * mutex, const
> pthread_mutexattr_t * attr);
>    int pthread_mutex_destroy (pthread_mutex_t * mutex);
>
> In C, you'd say:
>
>    pthread_mutex_t m;
>    pthread_mutex_init(&m, 0);
>    pthread_mutex_destroy(&m);
>
> In Lua you want to say:
>
>    m = new_mutex()
>    m:destroy()
>
> Hopefully with a minimum of wrappings and allocations.

I don't think it can be done as long as you're missing the size. I was
thinking about ØMQ before, which has a `zmq_ctx_new()` function which
gives you back a `void*`, which is opaque but can be given a metatable.
Obviously the key difference is that the library itself has allocates
storage. Or something like `getaddrinfo` which also does internal
allocation. In this case`pthread_mutex_init` just initializes and
assumes it has a big enough blob of memory.

On my system a pthread_mutext_t is 64 bytes (OS X 64 bit), but with a
bit of digging you could probably get the sizes for different platforms
and malloc appropriately sized chunks and hand those over to
`pthread_mutex_init`. Or create a C wrapper. Or copy struct definitions
(which is probably really tedious for something like pthreads).

This works for me (at least it doesn't segfault):

```
local ffi = require('ffi')
ffi.cdef[[
   void* malloc(size_t);
   void free(void*);

   typedef struct pthread_mutex_t_ pthread_mutex_t;
   typedef struct pthread_mutexattr_t_ pthread_mutexattr_t;
   int pthread_mutex_init (pthread_mutex_t* mutex, const
pthread_mutexattr_t * attr);
   int pthread_mutex_destroy (pthread_mutex_t* mutex);
]]

local C = ffi.C

local mutex_mt = { }
mutex_mt.__index = mutex_mt

function mutex_mt.destroy(self)
   C.pthread_mutex_destroy(self)
   C.free(self)
end
ffi.metatype('pthread_mutex_t', mutex_mt)

local mtx = ffi.cast('pthread_mutex_t*', C.malloc(64)); -- ick!
C.pthread_mutex_init(mtx, nil)
mtx:destroy()
```


Other related posts: