cregit-Linux how code gets into the kernel

Release 4.14 arch/um/os-Linux/signal.c

Directory: arch/um/os-Linux
/*
 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
 * Copyright (C) 2004 PathScale, Inc
 * Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
 * Licensed under the GPL
 */

#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <signal.h>
#include <strings.h>
#include <as-layout.h>
#include <kern_util.h>
#include <os.h>
#include <sysdep/mcontext.h>
#include <um_malloc.h>


void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
	[SIGTRAP]	= relay_signal,
	[SIGFPE]	= relay_signal,
	[SIGILL]	= relay_signal,
	[SIGWINCH]	= winch,
	[SIGBUS]	= bus_handler,
	[SIGSEGV]	= segv_handler,
	[SIGIO]		= sigio_handler,
	[SIGALRM]	= timer_handler
};


static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) { struct uml_pt_regs *r; int save_errno = errno; r = uml_kmalloc(sizeof(struct uml_pt_regs), UM_GFP_ATOMIC); if (!r) panic("out of memory"); r->is_user = 0; if (sig == SIGSEGV) { /* For segfaults, we want the data from the sigcontext. */ get_regs_from_mc(r, mc); GET_FAULTINFO_FROM_MC(r->faultinfo, mc); } /* enable signals if sig isn't IRQ signal */ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM)) unblock_signals(); (*sig_info[sig])(sig, si, r); errno = save_errno; free(r); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike8565.38%222.22%
Eli Cooper2821.54%111.11%
Al Viro64.62%222.22%
Richard Weinberger53.85%222.22%
Martin Pärtel53.85%111.11%
Anton Ivanov10.77%111.11%
Total130100.00%9100.00%

/* * These are the asynchronous signals. 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 SIGALRM_BIT 1 #define SIGALRM_MASK (1 << SIGALRM_BIT) static int signals_enabled; static unsigned int signals_pending; static unsigned int signals_active = 0;
void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) { int enabled; enabled = signals_enabled; if (!enabled && (sig == SIGIO)) { signals_pending |= SIGIO_MASK; return; } block_signals(); sig_handler_common(sig, si, mc); set_signals(enabled); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike4983.05%666.67%
Martin Pärtel58.47%111.11%
Al Viro35.08%111.11%
Richard Weinberger23.39%111.11%
Total59100.00%9100.00%


static void timer_real_alarm_handler(mcontext_t *mc) { struct uml_pt_regs *regs; regs = uml_kmalloc(sizeof(struct uml_pt_regs), UM_GFP_ATOMIC); if (!regs) panic("out of memory"); if (mc != NULL) get_regs_from_mc(regs, mc); timer_handler(SIGALRM, NULL, regs); free(regs); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike2741.54%440.00%
Eli Cooper2640.00%110.00%
Al Viro57.69%220.00%
Richard Weinberger34.62%110.00%
Anton Ivanov23.08%110.00%
Martin Pärtel23.08%110.00%
Total65100.00%10100.00%


void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) { int enabled; enabled = signals_enabled; if (!signals_enabled) { signals_pending |= SIGALRM_MASK; return; } block_signals(); signals_active |= SIGALRM_MASK; timer_real_alarm_handler(mc); signals_active &= ~SIGALRM_MASK; set_signals(enabled); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike3865.52%342.86%
Anton Ivanov1220.69%228.57%
Martin Pärtel58.62%114.29%
Al Viro35.17%114.29%
Total58100.00%7100.00%


void deliver_alarm(void) { timer_alarm_handler(SIGALRM, NULL, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Anton Ivanov16100.00%1100.00%
Total16100.00%1100.00%


void timer_set_signal_handler(void) { set_handler(SIGALRM); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike1083.33%150.00%
Anton Ivanov216.67%150.00%
Total12100.00%2100.00%


void set_sigstack(void *sig_stack, int size) { stack_t stack = { .ss_flags = 0, .ss_sp = sig_stack, .ss_size = size - sizeof(void *) }; if (sigaltstack(&stack, NULL) != 0) panic("enabling signal stack failed, errno = %d\n", errno); }

Contributors

PersonTokensPropCommitsCommitProp
Gennady Sharapov57100.00%1100.00%
Total57100.00%1100.00%

static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { [SIGSEGV] = sig_handler, [SIGBUS] = sig_handler, [SIGILL] = sig_handler, [SIGFPE] = sig_handler, [SIGTRAP] = sig_handler, [SIGIO] = sig_handler, [SIGWINCH] = sig_handler, [SIGALRM] = timer_alarm_handler };
static void hard_handler(int sig, siginfo_t *si, void *p) { struct ucontext *uc = p; mcontext_t *mc = &uc->uc_mcontext; unsigned long pending = 1UL << sig; do { int nested, bail; /* * pending comes back with one bit set for each * interrupt that arrived while setting up the stack, * plus a bit for this interrupt, plus the zero bit is * set if this is a nested interrupt. * If bail is true, then we interrupted another * handler setting up the stack. In this case, we * have to return, and the upper handler will deal * with this interrupt. */ bail = to_irq_stack(&pending); if (bail) return; nested = pending & 1; pending &= ~1; while ((sig = ffs(pending)) != 0){ sig--; pending &= ~(1 << sig); (*handlers[sig])(sig, (struct siginfo *)si, mc); } /* * Again, pending comes back with a mask of signals * that arrived while tearing down the stack. If this * is non-zero, we just go back, set up the stack * again, and handle the new interrupts. */ if (!nested) pending = from_irq_stack(nested); } while (pending); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike10776.98%342.86%
Al Viro2417.27%228.57%
Richard Weinberger53.60%114.29%
Martin Pärtel32.16%114.29%
Total139100.00%7100.00%


void set_handler(int sig) { struct sigaction action; int flags = SA_SIGINFO | SA_ONSTACK; sigset_t sig_mask; action.sa_sigaction = hard_handler; /* block irq ones */ sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGIO); sigaddset(&action.sa_mask, SIGWINCH); sigaddset(&action.sa_mask, SIGALRM); if (sig == SIGSEGV) flags |= SA_NODEFER; if (sigismember(&action.sa_mask, sig)) flags |= SA_RESTART; /* if it's an irq signal */ action.sa_flags = flags; action.sa_restorer = NULL; if (sigaction(sig, &action, NULL) < 0) 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); }

Contributors

PersonTokensPropCommitsCommitProp
Gennady Sharapov6741.36%114.29%
Jeff Dike5634.57%342.86%
Al Viro3622.22%228.57%
Anton Ivanov31.85%114.29%
Total162100.00%7100.00%


int change_sig(int signal, int on) { sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, signal); if (sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, NULL) < 0) return -errno; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Gennady Sharapov4279.25%133.33%
Américo Wang916.98%133.33%
Jeff Dike23.77%133.33%
Total53100.00%3100.00%


void block_signals(void) { signals_enabled = 0; /* * This must return with signals disabled, so this barrier * ensures that writes are flushed out before the return. * This might matter if gcc figures out how to inline this and * decides to shuffle this code into the caller. */ barrier(); }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike15100.00%4100.00%
Total15100.00%4100.00%


void unblock_signals(void) { int save_pending; if (signals_enabled == 1) return; /* * We loop because the IRQ handler returns with interrupts off. So, * interrupts may have arrived and we need to re-enable them and * recheck signals_pending. */ while (1) { /* * Save and reset save_pending after enabling signals. This * way, signals_pending won't be changed while we're reading it. */ signals_enabled = 1; /* * Setting signals_enabled and reading signals_pending must * happen in this order. */ barrier(); save_pending = signals_pending; if (save_pending == 0) return; signals_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. * * SIGIO's handler doesn't use siginfo or mcontext, * so they can be NULL. */ if (save_pending & SIGIO_MASK) sig_handler_common(SIGIO, NULL, NULL); /* Do not reenter the handler */ if ((save_pending & SIGALRM_MASK) && (!(signals_active & SIGALRM_MASK))) timer_real_alarm_handler(NULL); /* Rerun the loop only if there is still pending SIGIO and not in TIMER handler */ if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK)) return; } }

Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike5550.46%763.64%
Anton Ivanov3128.44%218.18%
Gennady Sharapov2018.35%19.09%
Martin Pärtel32.75%19.09%
Total109100.00%11100.00%


int get_signals(void) { return signals_enabled; }

Contributors

PersonTokensPropCommitsCommitProp
Gennady Sharapov990.00%150.00%
Jeff Dike110.00%150.00%
Total10100.00%2100.00%


int set_signals(int enable) { int ret; if (signals_enabled == enable) return enable; ret = signals_enabled; if (enable) unblock_signals(); else block_signals(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Gennady Sharapov2873.68%150.00%
Jeff Dike1026.32%150.00%
Total38100.00%2100.00%


int os_is_signal_stack(void) { stack_t ss; sigaltstack(NULL, &ss); return ss.ss_flags & SS_ONSTACK; }

Contributors

PersonTokensPropCommitsCommitProp
Richard Weinberger25100.00%1100.00%
Total25100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Jeff Dike55549.25%1750.00%
Gennady Sharapov23520.85%12.94%
Al Viro11710.38%617.65%
Anton Ivanov817.19%25.88%
Eli Cooper544.79%12.94%
Richard Weinberger453.99%38.82%
Martin Pärtel282.48%12.94%
Américo Wang100.89%25.88%
Sergei Trofimovich20.18%12.94%
Total1127100.00%34100.00%
Directory: arch/um/os-Linux
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.