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)); }