[haiku-development] Re: correct way to acquire_sem_etc()

  • From: Stephan Assmus <superstippi@xxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Thu, 30 Oct 2008 10:47:20 +0100

Ingo Weinhold wrote:
> 
> On 2008-10-29 at 23:23:33 [+0100], François Revol <revol@xxxxxxx> wrote:
> > >
> > > could someone help me with an acquire_sem_etc() problem? I am unsure 
> > > about
> > > the B_CAN_INTERRUPT flag and handling B_INTERRUPTED as the error code.
> > 
> > userland acquires are always interruptible.
> > Usually you don't want to be interruptible when you implement locking 
> > primitives, to avoid screwing up the state.
> > 
> > > When exactly do I want acquire_sem_etc() to be interruptable, and who 
> > > can
> > > interrupt me?
> > 
> > For things like read() hooks in drivers, when waiting for a buffer, 
> > it's desirable to be interruptible, so someone can actually hit CTRL-C 
> > in a terminal and get the desired behaviour.
> > In general I think anything that waits for an event with a long timeout 
> > should be interruptible.
> > 
> > Anyone who can send unmasked signals to the current thread can 
> > interrupt.
> 
> The suspend_thread() + resume_thread() combo does also interrupt, so does 
> debug_thread(). There might be other situations -- grep through the 
> kernel code for thread_interrupt(), if you're interested.
> 
> > Sometimes, even in locking primitives, it's done as while 
> > (acquire_sem_etc(s, B_CAN_INTERRUPT, ...) == B_INTERRUPTED);
> > 
> > This might be to eat signals and avoid delaying them instead, though 
> > I'm not sure.
> > I've seen that in the NFS addon code for ex.
> > It can't be to let the thread handle the signal, as it won't be done 
> > until it actually exit from the syscall...
> 
> If that is done in kernel code, it's buggy. Signals are only handled 
> right before leaving the kernel, that is this would become a busy loop.
> 
> > > As for the specific problem I am trying to fix: In the usb_hid driver,
> > > Michael and I use a USB interrupt transfer callback semaphore. In 
> > > other
> > > words, the thread that does ioctl() on the driver schedules an USB 
> > > interrupt transfer, then it blocks on a semaphore which has been 
> > > created
> > > like this:
> 
> If this is guaranteed to be done in a short time (I'm talking ms here), 
> the acquire_sem_etc() probably doesn't need to be interruptable. If it 
> can potentially take a long time (even if that's only in cases of 
> hardware errors or the like), it really should be interruptable and the 
> ioctl() should return immediately when that happens. One potential 
> problem is that there's probably some kind of cleanup needed in such a 
> case. Also the operation might still be performed successfully after all, 
> so the caller might thus get out of sync with its view of the device.
> 
> A kind of middle-ground is the flag B_KILL_CAN_INTERRUPT. It works like 
> B_CAN_INTERRUPT, iff the thread has received a kill signal. I.e. neither 
> SIGWINCH or Ctrl-C wouldn't interrupt it, but "kill -9" or 
> ProcessController Kill would. That doesn't change the need for cleanup 
> (if any), but at least one doesn't need to worry about the caller getting 
> a wrong picture of the situation, since it will never see userland again.
> 
> BTW, if you make the ioctl() interruptable you might want to consider 
> making it automatically restartable.

Ok, am I summing up correctly that I do want to use B_CAN_INTERRUPT, but 
then if I get B_INTERRUPTED as the return code from acquire_sem_etc() -> 
treat that as error and bail out. In another words, I wouldn't get 
interrupted unintentionally by "something unrelated", would I?

Best regards,
-Stephan



Other related posts: