Re: Problem with ucontext_t struct in signal handler

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



XComp wrote:

> > In any case, I don't think that you can rely upon the old_context
> > being usable once you leave the signal handler. Even if you copy the
> > contents, the uc_mcontext field may not be meaningful outside of the
> > handler.
> 
> So you think that solving the problem in this way will lead me in a  
> dead end?
> But I am confused because of the fact that it works sometimes.  
> Shouldn't it work the whole time or at no time only?

Intermittent faults are common with multi-threaded programming.

If a register is getting trashed, that will matter if you actually
need the register's value, but not if you're about to store a new
value there.

Looking at the disassembly:

	movl	$0, i
.L2:
	cmpl	$99999999, i
	jg	.L3
	incl	i
	jmp	.L2
.L3:

with absolute addresses:

 8048606:	movl   $0, i
 804860d:	
 8048610:	cmpl   $99999999, i
 8048617:	
 804861a:	jg     0x8048624
 804861c:	incl   i
 8048622:	jmp    0x8048610
 8048624:	...

my guess is that the flags aren't being saved, so when the signal
occurs between the "cmpl" and "jg" instructions, the sign flag is
being cleared, triggering the jump prematurely.

Adding the following:

	printf("\nold_context.uc_mcontext.gregs[REG_EFL] = %08x\n",
		 ((ucontext_t*) old_context)->uc_mcontext.gregs[REG_EFL]);
	printf("\nold_context.uc_mcontext.gregs[REG_IPL] = %08x\n",
		 ((ucontext_t*) old_context)->uc_mcontext.gregs[REG_EIP]);
shows the following:

	[Signal Handler]	SIGPROF was raised at  21883912...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000203
	old_context.uc_mcontext.gregs[REG_IPL] = 08048622
	[Signal Handler]	SIGPROF was raised at  43508833...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000203
	old_context.uc_mcontext.gregs[REG_IPL] = 08048610
	[Signal Handler]	SIGPROF was raised at  65140032...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000297
	old_context.uc_mcontext.gregs[REG_IPL] = 0804861a
	[Thread Function]	Error: 1st counting  didn't finished (65140032)...

More precisely, in the cases where it fails, EIP is always 0x0804861a
(the "jg" instruction), and EFL always has the sign flag (0x80) set.
In the cases where it succeeds:

	[Signal Handler]	SIGPROF was raised at  22107659...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000297
	old_context.uc_mcontext.gregs[REG_IPL] = 0804861c
	[Signal Handler]	SIGPROF was raised at  43727791...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000207
	old_context.uc_mcontext.gregs[REG_IPL] = 08048610
	[Signal Handler]	SIGPROF was raised at  65357434...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000203
	old_context.uc_mcontext.gregs[REG_IPL] = 08048610
	[Signal Handler]	SIGPROF was raised at  86987791...
	old_context.uc_mcontext.gregs[REG_EFL] = 00000283
	old_context.uc_mcontext.gregs[REG_IPL] = 0804861c
	[Thread Function]	1st counting worked  fine...

the above scenario never occurs.

It appears that you can't even use old_context to jump out of the
handler. In fact, the setcontext(2) manual page says:

       If  the	context	 was  obtained by a call to a signal handler, then old
       standard text says that "program execution continues with  the  program
       instruction following the instruction interrupted by the signal".  How-
       ever, this sentence was removed in SUSv2, and the  present  verdict  is
       "the result is unspecified".

I suspect that by the time that the kernel passes control to
user-space, the flags which libc saves are no longer correct. If
that's the case, the only solution is to return from the signal
handler back into the kernel, and allow the kernel to restore the
registers.

Note that the original code doesn't have this problem. The
swapcontext() which jumps out of the signal handler into user-space
jumps to a context which has just been created by makecontext() to
invoke scheduler().

And scheduler() never resumes a saved user-space context. The context
which it passes to setcontext() is either the original context created
by makecontext(), or it is the signal-space context which was saved
from within the signal handler by the swapcontext(). In the latter
case, the task resumes within the signal handler, from which it
returns normally.

So the code never attempts to resume a saved user-space context from
within the signal handler. From the perspective of the thread1() or
thread2() function, it gets a signal, enters the signal handler, then
(after all of the other tasks have had a turn) leaves the signal
handler.

-- 
Glynn Clements <glynn@xxxxxxxxxxxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Assembler]     [Git]     [Kernel List]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [C Programming]     [Yosemite Campsites]     [Yosemite News]     [GCC Help]

  Powered by Linux