| 1 | /* | 
|---|
| 2 |  * sys_kill.c - Kernel function implementing the "kill" system call. | 
|---|
| 3 |  *  | 
|---|
| 4 |  * Author    Alain Greiner     (2016,2017,2018,2019,2020) | 
|---|
| 5 |  * | 
|---|
| 6 |  * Copyright (c)  UPMC Sorbonne Universites | 
|---|
| 7 |  * | 
|---|
| 8 |  * This file is part of ALMOS-MKH. | 
|---|
| 9 |  * | 
|---|
| 10 |  * ALMOS-MKH is free software; you can redistribute it and/or modify it | 
|---|
| 11 |  * under the terms of the GNU General Public License as published by | 
|---|
| 12 |  * the Free Software Foundation; version 2.0 of the License. | 
|---|
| 13 |  * | 
|---|
| 14 |  * ALMOS-MKH is distributed in the hope that it will be useful, but | 
|---|
| 15 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 16 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 17 |  * General Public License for more details. | 
|---|
| 18 |  * | 
|---|
| 19 |  * You should have received a copy of the GNU General Public License | 
|---|
| 20 |  * along with ALMOS-MKH; if not, write to the Free Software Foundation, | 
|---|
| 21 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
| 22 |  */ | 
|---|
| 23 |  | 
|---|
| 24 | #include <kernel_config.h> | 
|---|
| 25 | #include <hal_kernel_types.h> | 
|---|
| 26 | #include <hal_irqmask.h> | 
|---|
| 27 | #include <errno.h> | 
|---|
| 28 | #include <thread.h> | 
|---|
| 29 | #include <printk.h> | 
|---|
| 30 | #include <process.h> | 
|---|
| 31 | #include <shared_syscalls.h> | 
|---|
| 32 | #include <cluster.h> | 
|---|
| 33 | #include <rpc.h> | 
|---|
| 34 |  | 
|---|
| 35 | #include <syscalls.h> | 
|---|
| 36 |  | 
|---|
| 37 |  | 
|---|
| 38 | #if DEBUG_SYS_KILL | 
|---|
| 39 | //////////////////////////////////////////// | 
|---|
| 40 | static char* sig_type_str( uint32_t sig_id ) | 
|---|
| 41 | { | 
|---|
| 42 |     switch( sig_id ) | 
|---|
| 43 |     { | 
|---|
| 44 |         case SIGKILL: return "SIGKILL"; | 
|---|
| 45 |         case SIGSTOP: return "SIGSTOP"; | 
|---|
| 46 |         case SIGCONT: return "SIGCONT"; | 
|---|
| 47 |         default:      return "undefined"; | 
|---|
| 48 |     } | 
|---|
| 49 | } | 
|---|
| 50 | #endif | 
|---|
| 51 |  | 
|---|
| 52 |  | 
|---|
| 53 | /////////////////////////// | 
|---|
| 54 | int sys_kill( pid_t    pid, | 
|---|
| 55 |               uint32_t sig_id ) | 
|---|
| 56 | { | 
|---|
| 57 |     xptr_t      owner_xp;          // extended pointer on process in owner cluster | 
|---|
| 58 |     cxy_t       owner_cxy;         // process owner cluster | 
|---|
| 59 |     process_t * owner_ptr;         // local pointer on process in owner cluster | 
|---|
| 60 |     xptr_t      parent_xp;         // extended pointer on parent process | 
|---|
| 61 |     cxy_t       parent_cxy;        // parent process cluster | 
|---|
| 62 |     process_t * parent_ptr;        // local pointer on parent process | 
|---|
| 63 |     thread_t  * parent_main_ptr;   // local pointer on parent main thread | 
|---|
| 64 |     xptr_t      parent_main_xp;    // extended pointer on parent main thread | 
|---|
| 65 |  | 
|---|
| 66 |     thread_t  * this    = CURRENT_THREAD; | 
|---|
| 67 |     process_t * process = this->process; | 
|---|
| 68 |  | 
|---|
| 69 | #if DEBUG_SYS_KILL || DEBUG_SYSCALLS_ERROR || CONFIG_INSTRUMENTATION_SYSCALLS | 
|---|
| 70 | uint64_t     tm_start = hal_get_cycles(); | 
|---|
| 71 | #endif | 
|---|
| 72 |  | 
|---|
| 73 | #if DEBUG_SYS_KILL | 
|---|
| 74 | if( DEBUG_SYS_KILL < tm_start ) | 
|---|
| 75 | printk("\n[%s] thread[%x,%x] enter : %s to process %x / cycle %d\n", | 
|---|
| 76 | __FUNCTION__, this->process->pid, this->trdid, | 
|---|
| 77 | sig_type_str(sig_id), pid, (uint32_t)tm_start ); | 
|---|
| 78 | #endif | 
|---|
| 79 |  | 
|---|
| 80 |     // get pointers on process descriptor in owner cluster | 
|---|
| 81 |     owner_xp  = cluster_get_owner_process_from_pid( pid ); | 
|---|
| 82 |     owner_cxy = GET_CXY( owner_xp ); | 
|---|
| 83 |     owner_ptr = GET_PTR( owner_xp ); | 
|---|
| 84 |      | 
|---|
| 85 | #if (DEBUG_SYS_KILL & 1) | 
|---|
| 86 | if( DEBUG_SYS_KILL < tm_start ) | 
|---|
| 87 | printk("\n[%s] thread[%x,%x] get target process descriptor %x in owner cluster %x\n", | 
|---|
| 88 | __FUNCTION__ , this->process->pid, this->trdid, owner_ptr, owner_cxy ); | 
|---|
| 89 | #endif | 
|---|
| 90 |  | 
|---|
| 91 |     // check process found | 
|---|
| 92 |     if( owner_xp == XPTR_NULL) | 
|---|
| 93 |     { | 
|---|
| 94 |  | 
|---|
| 95 | #if DEBUG_SYSCALLS_ERROR | 
|---|
| 96 | if( DEBUG_SYSCALLS_ERROR < tm_start ) | 
|---|
| 97 | printk("\n[ERROR] in %s : thread[%x,%x] / process %x not found\n", | 
|---|
| 98 | __FUNCTION__, process->pid, this->trdid, pid ); | 
|---|
| 99 | #endif | 
|---|
| 100 |         this->errno = EINVAL; | 
|---|
| 101 |         return -1; | 
|---|
| 102 |     } | 
|---|
| 103 |  | 
|---|
| 104 |     // get parent process descriptor pointers | 
|---|
| 105 |     parent_xp  = (xptr_t)hal_remote_l64( XPTR( owner_cxy , &owner_ptr->parent_xp ) ); | 
|---|
| 106 |     parent_cxy = GET_CXY( parent_xp ); | 
|---|
| 107 |     parent_ptr = GET_PTR( parent_xp ); | 
|---|
| 108 |  | 
|---|
| 109 | #if (DEBUG_SYS_KILL & 1) | 
|---|
| 110 | if( DEBUG_SYS_KILL < tm_start ) | 
|---|
| 111 | printk("\n[%s] thread[%x,%x] get parent process descriptor %x in cluster %x\n", | 
|---|
| 112 | __FUNCTION__ , this->process->pid, this->trdid, parent_ptr, parent_cxy ); | 
|---|
| 113 | #endif | 
|---|
| 114 |  | 
|---|
| 115 |     // get pointers on the parent process main thread | 
|---|
| 116 |     parent_main_ptr = hal_remote_lpt( XPTR( parent_cxy , &parent_ptr->th_tbl[0] ) );  | 
|---|
| 117 |     parent_main_xp  = XPTR( parent_cxy , parent_main_ptr ); | 
|---|
| 118 |  | 
|---|
| 119 |     // analyse signal type / supported values are : 0, SIGSTOP, SIGCONT, SIGKILL | 
|---|
| 120 |     switch( sig_id ) | 
|---|
| 121 |     { | 
|---|
| 122 |         case 0 :          // does nothing | 
|---|
| 123 |         { | 
|---|
| 124 |             break; | 
|---|
| 125 |         } | 
|---|
| 126 |         case SIGSTOP:     // block all target process threads | 
|---|
| 127 |         { | 
|---|
| 128 |             // block all threads in all clusters | 
|---|
| 129 |             process_sigaction( pid , BLOCK_ALL_THREADS ); | 
|---|
| 130 |  | 
|---|
| 131 | #if (DEBUG_SYS_KILL & 1) | 
|---|
| 132 | if( DEBUG_SYS_KILL < tm_start ) | 
|---|
| 133 | printk("\n[%s] thread[%x,%x] blocked all threads of process %x\n", | 
|---|
| 134 | __FUNCTION__ , this->process->pid, this->trdid, pid ); | 
|---|
| 135 | #endif | 
|---|
| 136 |             // atomically update owner process termination state | 
|---|
| 137 |             hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) , | 
|---|
| 138 |                                   PROCESS_TERM_STOP ); | 
|---|
| 139 |  | 
|---|
| 140 |             // unblock the parent process main thread | 
|---|
| 141 |             thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT ); | 
|---|
| 142 |  | 
|---|
| 143 |             // calling thread deschedules when it is itself a target thread | 
|---|
| 144 |             if( this->process->pid == pid ) | 
|---|
| 145 |             { | 
|---|
| 146 |  | 
|---|
| 147 | #if (DEBUG_SYS_KILL & 1) | 
|---|
| 148 | if( DEBUG_SYS_KILL < tm_start ) | 
|---|
| 149 | printk("\n[%s] thread[%x,%x] is a target thread => deschedule\n", | 
|---|
| 150 | __FUNCTION__ , this->process->pid, this->trdid ); | 
|---|
| 151 | #endif | 
|---|
| 152 |                 sched_yield("block itself"); | 
|---|
| 153 |             } | 
|---|
| 154 |  | 
|---|
| 155 |             break; | 
|---|
| 156 |         } | 
|---|
| 157 |         case SIGCONT:     // unblock all target process threads | 
|---|
| 158 |         { | 
|---|
| 159 |             // unblock all threads in all clusters | 
|---|
| 160 |             process_sigaction( pid , UNBLOCK_ALL_THREADS ); | 
|---|
| 161 |  | 
|---|
| 162 |             // atomically update owner process termination state | 
|---|
| 163 |             hal_remote_atomic_and( XPTR( owner_cxy , &owner_ptr->term_state ) , | 
|---|
| 164 |                                    ~PROCESS_TERM_STOP ); | 
|---|
| 165 |  | 
|---|
| 166 |             // unblock the parent process main thread  | 
|---|
| 167 |             thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT ); | 
|---|
| 168 |  | 
|---|
| 169 |             break; | 
|---|
| 170 |         } | 
|---|
| 171 |         case SIGKILL: | 
|---|
| 172 |         { | 
|---|
| 173 |             // a process cannot kill itself | 
|---|
| 174 |             if( (pid == process->pid) )  | 
|---|
| 175 |             { | 
|---|
| 176 |  | 
|---|
| 177 | #if DEBUG_SYSCALLS_ERROR | 
|---|
| 178 | if( DEBUG_SYSCALLS_ERROR < tm_start ) | 
|---|
| 179 | printk("\n[ERROR] in %s : thread[%x,%x] / process %x cannot kill itself\n", | 
|---|
| 180 | __FUNCTION__, process->pid, this->trdid, pid ); | 
|---|
| 181 | #endif | 
|---|
| 182 |                 this->errno = EINVAL; | 
|---|
| 183 |                 return -1; | 
|---|
| 184 |             } | 
|---|
| 185 |  | 
|---|
| 186 |             // processe INIT cannot be killed | 
|---|
| 187 |             if( pid == 1 ) | 
|---|
| 188 |             { | 
|---|
| 189 |  | 
|---|
| 190 | #if DEBUG_SYSCALLS_ERROR | 
|---|
| 191 | if( DEBUG_SYSCALLS_ERROR < tm_start ) | 
|---|
| 192 | printk("\n[ERROR] in %s : thread[%x,%x] / process_init cannot be killed\n", | 
|---|
| 193 |  __FUNCTION__, process->pid, this->trdid); | 
|---|
| 194 | #endif | 
|---|
| 195 |                         this->errno = EINVAL; | 
|---|
| 196 |                 return -1; | 
|---|
| 197 |             } | 
|---|
| 198 |  | 
|---|
| 199 |             // remove process from TXT list | 
|---|
| 200 |             process_txt_detach( owner_xp ); | 
|---|
| 201 |  | 
|---|
| 202 |             // close all open files | 
|---|
| 203 |             process_fd_clean_all( owner_xp ); | 
|---|
| 204 |  | 
|---|
| 205 |             // mark for delete all threads in all clusters, but the main  | 
|---|
| 206 |             process_sigaction( pid , DELETE_ALL_THREADS ); | 
|---|
| 207 |  | 
|---|
| 208 |             // block main thread | 
|---|
| 209 |             xptr_t main_xp = XPTR( owner_cxy , &owner_ptr->th_tbl[0] ); | 
|---|
| 210 |             thread_block( main_xp , THREAD_BLOCKED_GLOBAL ); | 
|---|
| 211 |  | 
|---|
| 212 |             // atomically update owner process descriptor term_state to ask | 
|---|
| 213 |             // the parent process sys_wait() function to delete this main thread | 
|---|
| 214 |             hal_remote_atomic_or( XPTR( owner_cxy , &owner_ptr->term_state ) , | 
|---|
| 215 |                                   PROCESS_TERM_KILL ); | 
|---|
| 216 |  | 
|---|
| 217 |             // unblock the parent process main thread  | 
|---|
| 218 |             thread_unblock( parent_main_xp , THREAD_BLOCKED_WAIT ); | 
|---|
| 219 |  | 
|---|
| 220 |             break; | 
|---|
| 221 |         } | 
|---|
| 222 |         default: | 
|---|
| 223 |         { | 
|---|
| 224 |  | 
|---|
| 225 | #if DEBUG_SYSCALLS_ERROR | 
|---|
| 226 | if( DEBUG_SYSCALLS_ERROR < tm_start ) | 
|---|
| 227 | printk("\n[ERROR] in %s : thread[%x,%x] / illegal signal %d\n", | 
|---|
| 228 | __FUNCTION__, process->pid, this->trdid, sig_id ); | 
|---|
| 229 | #endif | 
|---|
| 230 |             this->errno = EINVAL; | 
|---|
| 231 |             return -1; | 
|---|
| 232 |         } | 
|---|
| 233 |     } | 
|---|
| 234 |      | 
|---|
| 235 |     hal_fence(); | 
|---|
| 236 |  | 
|---|
| 237 | #if (DEBUG_SYS_KILL || CONFIG_INSTRUMENTATION_SYSCALLS) | 
|---|
| 238 | uint64_t     tm_end = hal_get_cycles(); | 
|---|
| 239 | #endif | 
|---|
| 240 |  | 
|---|
| 241 | #if DEBUG_SYS_KILL | 
|---|
| 242 | if( DEBUG_SYS_KILL < tm_end ) | 
|---|
| 243 | printk("\n[%s] thread[%x,%x] exit / process %x / %s / cycle %d\n", | 
|---|
| 244 | __FUNCTION__ , this->process->pid, this->trdid, pid, | 
|---|
| 245 | sig_type_str(sig_id), (uint32_t)tm_end ); | 
|---|
| 246 | #endif | 
|---|
| 247 |  | 
|---|
| 248 | #if CONFIG_INSTRUMENTATION_SYSCALLS | 
|---|
| 249 | hal_atomic_add( &syscalls_cumul_cost[SYS_KILL] , tm_end - tm_start ); | 
|---|
| 250 | hal_atomic_add( &syscalls_occurences[SYS_KILL] , 1 ); | 
|---|
| 251 | #endif | 
|---|
| 252 |  | 
|---|
| 253 |         return 0; | 
|---|
| 254 |  | 
|---|
| 255 | }  // end sys_kill() | 
|---|
| 256 |  | 
|---|