/* * signal.c - signal-management related operations implementation * * Author Alain Greiner (2016,2017) * * 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; } ////////////////////////////////////// void signal_rise( 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 ); } // end signal_rise() /////////////////////////////////////////// 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 sys_kill( pid_t pid, uint32_t sig) { cxy_t owner_cxy; // process owner cluster lpid_t owner_lpid; // local process identifier xptr_t root_xp; // extended pointer on root of xlist of process copies xptr_t lock_xp; // extended pointer on remote_spinlock protecting this list xptr_t iter_xp; // iterator for process copies list xptr_t process_xp; // local pointer on process copy cxy_t process_cxy; // cluster of process copy process_t * process_ptr; // local pointer on process copy error_t error; // get local pointer on local cluster manager cluster_t * cluster = LOCAL_CLUSTER; // get owner process cluster and lpid owner_cxy = CXY_FROM_PID( pid ); owner_lpid = LPID_FROM_PID( pid ); // get extended pointers on copies root and lock root_xp = XPTR( owner_cxy , &cluster->copies_root[lpid] ); lock_xp = XPTR( owner_cxy , &cluster->copies_lock[lpid] ); // take the lock protecting the copies remote_spinlock_lock( lock_xp ); // TODO the loop below sequencialize the RPCs // they could be pipelined... // traverse the list of copies XLIST_FOREACH( root_xp , iter_xp ) { process_xp = XLIST_ELEMENT( iter_xp , process_t , copies_list ); process_cxy = GET_CXY( process_xp ); process_ptr = (process_t *)GET_PTR( process_xp ); if( process_xy == local_cxy ) // process copy is local { error = signal_rise( process_ptr , sig ); } else // process copy is remote { rpc_signal_rise_client( process_cxy , process_ptr , sig ); } } return 0; } //////////////////////////////////// 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); } }