win32utils-devel@rubyforge.org
2004-Oct-23 16:13 UTC
[Win32utils-devel] win32-ipc, with blocks (code review please)
Does this look right? The places to look are wait and wait_for_multiple
(which I modified to take the class as an argument, so that I could yield).
Dan
/****************************************************************************
* ipc.c - source for the win32-ipc package
****************************************************************************/
#include "ruby.h"
#include <windows.h>
#include "ipc.h"
static VALUE cIpcError;
static char error[MAX_STRING];
static VALUE ipc_init(VALUE self, VALUE obj){
IpcStruct* ptr;
Data_Get_Struct(self,IpcStruct,ptr);
ptr->handle = (HANDLE)NUM2UINT(obj);
return self;
}
static VALUE ipc_allocate(VALUE klass){
IpcStruct* ptr = malloc(sizeof(IpcStruct));
return Data_Wrap_Struct(klass,0,ipc_free,ptr);
}
static VALUE wait_for_multiple(VALUE klass,VALUE arr,
BOOL fWaitAll,DWORD dwTimeOut)
{
DWORD dwWait;
static HANDLE *handles = NULL;
int i,len = RARRAY(arr)->len;
if(len==0){
rb_raise(cIpcError,"No objects to wait for");
}
REALLOC_N(handles,HANDLE,len);
for(i=0; i<len; i++) {
handles[i] = (HANDLE)NUM2UINT(RARRAY(arr)->ptr[i]);
}
dwWait = WaitForMultipleObjects(len,handles,fWaitAll,dwTimeOut);
// Yield block if signalled and block is provided
if((dwWait >= WAIT_OBJECT_0) && (dwWait < WAIT_OBJECT_0 +
len)){
if(rb_block_given_p()){
rb_yield(klass);
}
return INT2NUM(dwWait - WAIT_OBJECT_0 + 1); // signalled
}
if((dwWait >= WAIT_ABANDONED_0) && (dwWait < WAIT_ABANDONED_0 +
len)){
return INT2NUM(-(dwWait - WAIT_ABANDONED_0 + 1)); // an abandoned
mutex
}
if(dwWait == WAIT_TIMEOUT){
return INT2NUM(0); // Timed out
}
return Qnil;
}
static VALUE ipc_wait_any(int argc, VALUE* argv, VALUE klass)
{
VALUE rbObject, rbTimeout;
DWORD dwTimeout = INFINITE;
rb_scan_args(argc,argv,"11",&rbObject,&rbTimeout);
if(TYPE(rbObject)!=T_ARRAY) {
rb_raise(rb_eArgError,"Invalid Object Handles");
}
if(rbTimeout!=Qnil) dwTimeout = NUM2UINT(INFINITE);
return wait_for_multiple(klass,rbObject,FALSE,dwTimeout);
}
static VALUE ipc_wait_all(int argc, VALUE* argv, VALUE klass)
{
VALUE rbObject, rbTimeout;
DWORD dwTimeout = INFINITE;
rb_scan_args(argc,argv,"11",&rbObject,&rbTimeout);
if(TYPE(rbObject)!=T_ARRAY) {
rb_raise(rb_eArgError,"Invalid Object Handles");
}
if(rbTimeout!=Qnil) dwTimeout = NUM2UINT(rbTimeout);
return wait_for_multiple(klass,rbObject,TRUE,dwTimeout);
}
static VALUE ipc_wait(int argc, VALUE* argv, VALUE self)
{
VALUE rbTimeout;
DWORD dwWait,dwTimeout = INFINITE;
IpcStruct* ptr;
Data_Get_Struct(self,IpcStruct,ptr);
rb_scan_args(argc,argv,"01",&rbTimeout);
if(rbTimeout!=Qnil){
dwTimeout = NUM2UINT(rbTimeout);
}
dwWait = WaitForSingleObject(ptr->handle,dwTimeout);
// If a block is provided, yield the block if signalled.
if(dwWait == WAIT_OBJECT_0){
if(rb_block_given_p()){
rb_yield(self);
}
return INT2NUM(1);
}
else if(dwWait == WAIT_ABANDONED_0){
return INT2NUM(-1);
}
else if(dwWait == WAIT_TIMEOUT){
return INT2NUM(0);
}
else{
return Qnil;
}
}
void Init_ipc()
{
VALUE mWin32, cIpc;
/* Modules and Classes */
mWin32 = rb_define_module("Win32");
cIpc = rb_define_class_under(mWin32, "Ipc", rb_cObject);
cIpcError =
rb_define_class_under(mWin32,"IpcError",rb_eStandardError);
// IPC class and instance methods
rb_define_alloc_func(cIpc,ipc_allocate);
rb_define_singleton_method(cIpc,"wait_any",ipc_wait_any,-1);
rb_define_singleton_method(cIpc,"wait_all",ipc_wait_all,-1);
rb_define_method(cIpc,"initialize",ipc_init,1);
rb_define_method(cIpc,"wait",ipc_wait,-1);
// Constants
rb_define_const(cIpc,"INFINITE",UINT2NUM(INFINITE));
rb_define_const(cIpc,"VERSION",rb_str_new2(WIN32_IPC_VERSION));
}
