Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 18922
b: refs/heads/master
c: 1d7173b
h: refs/heads/master
v: v3
  • Loading branch information
Jeff Dike authored and Linus Torvalds committed Jan 19, 2006
1 parent 37b281a commit 8eb8cf3
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 119 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 09ee011eb322c2072ec184a88763c250a5485d8b
refs/heads/master: 1d7173baf286c8b720f97f119ec92be43076ebde
19 changes: 19 additions & 0 deletions trunk/arch/um/include/longjmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef __UML_LONGJMP_H
#define __UML_LONGJMP_H

#include <setjmp.h>
#include "os.h"

#define UML_SIGLONGJMP(buf, val) do { \
siglongjmp(*buf, val); \
} while(0)

#define UML_SIGSETJMP(buf, enable) ({ \
int n; \
enable = get_signals(); \
n = sigsetjmp(*buf, 1); \
if(n != 0) \
set_signals(enable); \
n; })

#endif
12 changes: 0 additions & 12 deletions trunk/arch/um/os-Linux/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,8 @@ extern void scan_elf_aux( char **envp);
int main(int argc, char **argv, char **envp)
{
char **new_argv;
sigset_t mask;
int ret, i, err;

/* Enable all signals except SIGIO - in some environments, we can
* enter with some signals blocked
*/

sigemptyset(&mask);
sigaddset(&mask, SIGIO);
if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){
perror("sigprocmask");
exit(1);
}

#ifdef UML_CONFIG_CMDLINE_ON_HOST
/* Allocate memory for thread command lines */
if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){
Expand Down
30 changes: 10 additions & 20 deletions trunk/arch/um/os-Linux/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "process.h"
#include "irq_user.h"
#include "kern_util.h"
#include "longjmp.h"

#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
Expand Down Expand Up @@ -205,24 +206,13 @@ void init_new_thread_signals(int altstack)

int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
sigjmp_buf buf;
int n;

*jmp_ptr = &buf;
n = sigsetjmp(buf, 1);
if(n != 0)
return(n);
(*fn)(arg);
return(0);
sigjmp_buf buf;
int n, enable;

*jmp_ptr = &buf;
n = UML_SIGSETJMP(&buf, enable);
if(n != 0)
return(n);
(*fn)(arg);
return(0);
}

/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/
203 changes: 131 additions & 72 deletions trunk/arch/um/os-Linux/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,58 @@
#include "mode.h"
#include "os.h"

/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
* together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
* be able to profile all of UML, not just the non-critical sections. If
* profiling is not thread-safe, then that is not my problem. We can disable
* profiling when SMP is enabled in that case.
*/
#define SIGIO_BIT 0
#define SIGIO_MASK (1 << SIGIO_BIT)

#define SIGVTALRM_BIT 1
#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)

#define SIGALRM_BIT 2
#define SIGALRM_MASK (1 << SIGALRM_BIT)

static int signals_enabled = 1;
static int pending = 0;

void sig_handler(ARCH_SIGHDLR_PARAM)
{
struct sigcontext *sc;
int enabled;

/* Must be the first thing that this handler does - x86_64 stores
* the sigcontext in %rdx, and we need to save it before it has a
* chance to get trashed.
*/

ARCH_GET_SIGCONTEXT(sc, sig);

enabled = signals_enabled;
if(!enabled && (sig == SIGIO)){
pending |= SIGIO_MASK;
return;
}

block_signals();

CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
sig, sc);

set_signals(enabled);
}

extern int timer_irq_inited;

void alarm_handler(ARCH_SIGHDLR_PARAM)
static void real_alarm_handler(int sig, struct sigcontext *sc)
{
struct sigcontext *sc;

ARCH_GET_SIGCONTEXT(sc, sig);
if(!timer_irq_inited) return;
if(!timer_irq_inited){
signals_enabled = 1;
return;
}

if(sig == SIGALRM)
switch_timers(0);
Expand All @@ -46,17 +81,52 @@ void alarm_handler(ARCH_SIGHDLR_PARAM)

if(sig == SIGALRM)
switch_timers(1);

}

void alarm_handler(ARCH_SIGHDLR_PARAM)
{
struct sigcontext *sc;
int enabled;

ARCH_GET_SIGCONTEXT(sc, sig);

enabled = signals_enabled;
if(!signals_enabled){
if(sig == SIGVTALRM)
pending |= SIGVTALRM_MASK;
else pending |= SIGALRM_MASK;

return;
}

block_signals();

real_alarm_handler(sig, sc);
set_signals(enabled);
}

extern void do_boot_timer_handler(struct sigcontext * sc);

void boot_timer_handler(ARCH_SIGHDLR_PARAM)
{
struct sigcontext *sc;
int enabled;

ARCH_GET_SIGCONTEXT(sc, sig);

enabled = signals_enabled;
if(!enabled){
if(sig == SIGVTALRM)
pending |= SIGVTALRM_MASK;
else pending |= SIGALRM_MASK;
return;
}

block_signals();

do_boot_timer_handler(sc);
set_signals(enabled);
}

void set_sigstack(void *sig_stack, int size)
Expand All @@ -83,6 +153,7 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
{
struct sigaction action;
va_list ap;
sigset_t sig_mask;
int mask;

va_start(ap, flags);
Expand All @@ -95,7 +166,12 @@ void set_handler(int sig, void (*handler)(int), int flags, ...)
action.sa_flags = flags;
action.sa_restorer = NULL;
if(sigaction(sig, &action, NULL) < 0)
panic("sigaction failed");
panic("sigaction failed - errno = %d\n", errno);

sigemptyset(&sig_mask);
sigaddset(&sig_mask, sig);
if(sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) < 0)
panic("sigprocmask failed - errno = %d\n", errno);
}

int change_sig(int signal, int on)
Expand All @@ -108,91 +184,74 @@ int change_sig(int signal, int on)
return(!sigismember(&old, signal));
}

/* Both here and in set/get_signal we don't touch SIGPROF, because we must not
* disable profiling; it's safe because the profiling code does not interact
* with the kernel code at all.*/

static void change_signals(int type)
{
sigset_t mask;

sigemptyset(&mask);
sigaddset(&mask, SIGVTALRM);
sigaddset(&mask, SIGALRM);
sigaddset(&mask, SIGIO);
if(sigprocmask(type, &mask, NULL) < 0)
panic("Failed to change signal mask - errno = %d", errno);
}

void block_signals(void)
{
change_signals(SIG_BLOCK);
signals_enabled = 0;
}

void unblock_signals(void)
{
change_signals(SIG_UNBLOCK);
}
int save_pending;

/* These are the asynchronous signals. SIGVTALRM and SIGARLM are handled
* together under SIGVTALRM_BIT. SIGPROF is excluded because we want to
* be able to profile all of UML, not just the non-critical sections. If
* profiling is not thread-safe, then that is not my problem. We can disable
* profiling when SMP is enabled in that case.
*/
#define SIGIO_BIT 0
#define SIGVTALRM_BIT 1

static int enable_mask(sigset_t *mask)
{
int sigs;
if(signals_enabled == 1)
return;

sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT;
sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT;
sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT;
return(sigs);
/* We loop because the IRQ handler returns with interrupts off. So,
* interrupts may have arrived and we need to re-enable them and
* recheck pending.
*/
while(1){
/* Save and reset save_pending after enabling signals. This
* way, pending won't be changed while we're reading it.
*/
signals_enabled = 1;

save_pending = pending;
if(save_pending == 0)
return;

pending = 0;

/* We have pending interrupts, so disable signals, as the
* handlers expect them off when they are called. They will
* be enabled again above.
*/

signals_enabled = 0;

/* Deal with SIGIO first because the alarm handler might
* schedule, leaving the pending SIGIO stranded until we come
* back here.
*/
if(save_pending & SIGIO_MASK)
CHOOSE_MODE_PROC(sig_handler_common_tt,
sig_handler_common_skas, SIGIO, NULL);

if(save_pending & SIGALRM_MASK)
real_alarm_handler(SIGALRM, NULL);

if(save_pending & SIGVTALRM_MASK)
real_alarm_handler(SIGVTALRM, NULL);
}
}

int get_signals(void)
{
sigset_t mask;

if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0)
panic("Failed to get signal mask");
return(enable_mask(&mask));
return signals_enabled;
}

int set_signals(int enable)
{
sigset_t mask;
int ret;
if(signals_enabled == enable)
return enable;

sigemptyset(&mask);
if(enable & (1 << SIGIO_BIT))
sigaddset(&mask, SIGIO);
if(enable & (1 << SIGVTALRM_BIT)){
sigaddset(&mask, SIGVTALRM);
sigaddset(&mask, SIGALRM);
}

/* This is safe - sigprocmask is guaranteed to copy locally the
* value of new_set, do his work and then, at the end, write to
* old_set.
*/
if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
panic("Failed to enable signals");
ret = enable_mask(&mask);
sigemptyset(&mask);
if((enable & (1 << SIGIO_BIT)) == 0)
sigaddset(&mask, SIGIO);
if((enable & (1 << SIGVTALRM_BIT)) == 0){
sigaddset(&mask, SIGVTALRM);
sigaddset(&mask, SIGALRM);
}
if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
panic("Failed to block signals");
ret = signals_enabled;
if(enable)
unblock_signals();
else block_signals();

return(ret);
return ret;
}

void os_usr1_signal(int on)
Expand Down
Loading

0 comments on commit 8eb8cf3

Please sign in to comment.