Hi,

At Wed, 16 May 2007 15:40:08 +0900,
Pete wrote in [ruby-talk:251765]:
> void callback_from_handler(....){
> 	if (!rb_block_given_p() || !receiving || ...) return;	// do nothing unless active
>  	VALUE bev = rb_class_new_instance(... cBMidiEvent); // event data copied to new obj
> 	VALUE res = rb_yield(bev);	// pass event to code block
> 	if (RTEST(res)) {	// not nil or false -- used as termination signal
> 		receiving = false;
> 		release_sem();	// tell 'do_each' to wake up
> 	}
> }

From where is this function called?  Unless it's called as a
ruby method, you can't use rb_yield() in it.  You might assume
the block to bmidi_each() is accessible, it is never guaranteed
at all.

> VALUE bmidi_ensure(VALUE self) {
> 	if (receiving) {	// only if not terminated normally (details omitted...)
> 		release_sem();
> 	}
> 	receiving = false;
> 	return self;
> }
> 
> VALUE bmidi_doeach(VALUE self) {
>  	receiving = true;
>  	acquire_sem();	// sleep until woken (timeout etc omitted)
> 	return self;
> }


Since bmidi_ensure() won't get called until bmidi_doeach()
ends, the latter seems to success to acquire the semaphore only
when the callback released it.  At that time, the callback sets
receiving to false before the release, so the bmidi_ensure()
leaves the semaphore locked which acquired by bmidi_doeach(), I
guess.  In short, the sequence is wrong.

Anyway, you need to call rb_yield() in bmidi_each().

void
callback_from_handler(....)
{
    VALUE bev = rb_class_new_instance(... cBMidiEvent);
    acquire_sem();
    received_bmidievent = bev;  // pass event to 'each'
    release_sem();  // tell 'each' to wake up
}

VALUE
bmidi_each(VALUE self)
{
    VALUE res;

    rb_need_block();
    do {
        acquire_sem();
        VALUE bev = received_bmidievent;
        release_sem();
        res = rb_yield(bev);  // pass event to code block
    } while (RTEST(res));
    return self;
}

-- 
Nobu Nakada