/* * signal.c - signal-management related operations implementation * * Author Ghassan Almaless (2008,2009,2010,2011,2012) * Mohamed Lamine Karaoui (2015) * Alain Greiner (2016) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH. * * ALMOS-MKH is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include SIGNAL_HANDLER(kill_sigaction) { struct thread_s *this; this = CURRENT_THREAD; this->state = S_KERNEL; printk(INFO, "INFO: Recieved signal %d, pid %d, tid %x, core %d [ KILLED ]\n", sig, this->process->pid, this, cpu_get_id()); sys_thread_exit((void*)EINTR); } ////////////////////////////////////////////////// void signal_manager_init( process_t * process ) { memset(&process->sig_mgr, 0, sizeof(process->sig_mgr)); process->sig_mgr.sigactions[SIGCHLD] = SIG_IGNORE; process->sig_mgr.sigactions[SIGURG] = SIG_IGNORE; } //////////////////////////////////////// error_t signal_init( thread_t * thread ) { thread->info.sig_state = 0; thread->info.sig_mask = CURRENT_THREAD->info.sig_mask; return 0; } //////////////////////////////////////////////////// static error_t signal_rise_all( process_t * process, uint32_t sig ) { thread_t * thread; uint32_t i; spinlock_lock( &process->th_lock ); for( i = 0 ; i < process->th_nr ; i++ ) { thread = process->th_tbl[i]; hal_atomic_or( &thread->signals , (1 << sig) ); } spinlock_unlock( &process->th_lock ); sig_dmsg("\n[INFO] %s : %d threads have been signaled for process %d\n", __FUNCTION__, process->th_nr , process->pid ); return 0; } //////////////////////////////////////////////////// static error_t signal_rise_one( process_t * process, uint32_t sig ) { thread_t * thread; spinlock_lock( &process->th_lock ); //mdify to current_thread, not the one pointed by the sig_mgr ? if(process->sig_mgr.handler == NULL) thread = list_first(&process->th_root, struct thread_s, rope); else thread = process->sig_mgr.handler; spinlock_lock( &thread->lock ); thread->info.sig_state |= (1 << sig); spinlock_unlock( &thread->lock ); spinlock_unlock( &process->th_lock ); sig_dmsg("\n[INFO] %s : Thread %u of process %u has received signal %u. sig_state = %x\n", \ __FUNCTION__, thread_current_cpu(thread)->gid, \ process->pid, sig, thread->info.sig_state); return 0; } RPC_DECLARE( __signal_rise, \ RPC_RET( RPC_RET_PTR(error_t, err)), \ RPC_ARG( RPC_ARG_VAL(pid_t, pid), \ RPC_ARG_VAL(uint32_t, sig)) \ ) { process_t * process; struct hnode_s *hnode; /* Avoid killing process0 and init */ /* FIXME: Zero should not be hard-coded but obtains with something like MAIN_KERN */ if( ((pid == PID_MIN_GLOBAL) || (pid == PID_MIN_GLOBAL+1)) && (current_cid == 0) ) { *err = EPERM; sig_dmsg(1, "%s: can't kill process %u on cluster %u\n", \ __FUNCTION__, PID_GET_LOCAL(pid), current_cid); goto SYS_RISE_ERR_PID; } /* Step 1 : lock the process manager */ processs_manager_lock(); /* Step 2 : Get the process' address */ /* Case 1 : current cluster is the anchor and the owner. */ if ( PID_GET_CLUSTER(pid) == current_cid ) { sig_dmsg(1, "%s: process %u is in the processs manager array of cluster %u\n", \ __FUNCTION__, pid, current_cid); process = process_lookup(pid)->process; } else /* Case 2 : current cluster is not the anchor, so the struct * process_s is in its hash table. */ { sig_dmsg(1, "%s: process %u is in the processs manager hash table of cluster %u\n", \ __FUNCTION__, pid, current_cid); hnode = hfind(processs_manager_get_htable(), (void*)pid); process = ( process_t*) container_of(hnode, \ process_t, t_hnode); } /* Step 4 : check process' address */ if ( process == NULL ) { *err = ESRCH; goto SYS_RISE_ERR; } /* Step 5 : deliver signal */ if((sig == SIGTERM) || (sig == SIGKILL)) *err = signal_rise_all(process, sig); else *err = signal_rise_one(process, sig); /* Step 6 : unlock processs manager */ processs_manager_unlock(); return; SYS_RISE_ERR: processs_manager_unlock(); SYS_RISE_ERR_PID: sig_dmsg(1, "%s: Cluster %u has not deliver signal %u to process %u (err %u)\n", \ __FUNCTION__, current_cid, sig, err ); return; } ////////////////////////////////// error_t signal_rise( pid_t pid, cxy_t location, uint32_t sig) { error_t err; /* Check location error */ if ( location == CID_NULL ) { err = ESRCH; printk(WARNING, "%s: there is no process with pid %u\n", \ __FUNCTION__, pid); return err; } err = EAGAIN; RCPC( location, RPC_PRIO_SIG_RISE, __signal_rise, \ RPC_RECV( RPC_RECV_OBJ(err) ), \ RPC_SEND( RPC_SEND_OBJ(pid), \ RPC_SEND_OBJ(sig)) \ ); return err; } //////////////////////////////////// void signal_notify( thread_s * this) { register uint32_t sig_state; register uint32_t sig; register struct sig_mgr_s *sig_mgr; uint32_t irq_state; sig_state = this->info.sig_state & this->info.sig_mask; sig = 0; while((sig_state != 0) && ((sig_state & 0x1) == 0) && (sig < SIG_NR)) { sig ++; sig_state >>= 1; } if(sig) { cpu_disable_all_irq(&irq_state); if(thread_isSignaled(this)) { cpu_restore_irq(irq_state); return; } thread_set_signaled(this); cpu_restore_irq(irq_state); spinlock_lock(&this->lock); this->info.sig_state &= ~(1 << sig); spinlock_unlock(&this->lock); sig_mgr = &this->process->sig_mgr; if(sig_mgr->sigactions[sig] == SIG_IGNORE) return; if(sig_mgr->sigactions[sig] == SIG_DEFAULT) kill_sigaction(sig); cpu_signal_notify(this, sig_mgr->sigactions[sig], sig); } }