[Win32utils-devel] win32-ipc, with blocks (code review please)

win32utils-devel at rubyforge.org win32utils-devel at rubyforge.org
Sat Oct 23 16:12:10 EDT 2004


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




More information about the win32utils-devel mailing list