Changeset 23 for trunk/kernel/syscalls/sys_thread_join.c
- Timestamp:
- Jun 18, 2017, 10:06:41 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/syscalls/sys_thread_join.c
r1 r23 1 1 /* 2 * kern/sys_thread_join.c - passive wait on the end of a given thread2 * sys_thread_join.c - passive wait on the end of a given thread. 3 3 * 4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless 4 * Authors Alain Greiner (2016,2017) 5 * 5 6 * Copyright (c) 2011,2012 UPMC Sorbonne Universites 6 7 * 7 * This file is part of ALMOS- kernel.8 * This file is part of ALMOS-MKH. 8 9 * 9 * ALMOS- kernelis free software; you can redistribute it and/or modify it10 * ALMOS-MKH is free software; you can redistribute it and/or modify it 10 11 * under the terms of the GNU General Public License as published by 11 12 * the Free Software Foundation; version 2.0 of the License. 12 13 * 13 * ALMOS- kernelis distributed in the hope that it will be useful, but14 * ALMOS-MKH is distributed in the hope that it will be useful, but 14 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU … … 17 18 * 18 19 * You should have received a copy of the GNU General Public License 19 * along with ALMOS- kernel; if not, write to the Free Software Foundation,20 * along with ALMOS-MKH; if not, write to the Free Software Foundation, 20 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 22 */ 22 23 23 #include <list.h> 24 #include <hal_types.h> 25 #include <hal_remote.h> 26 #include <hal_special.h> 24 27 #include <thread.h> 28 #include <vmm.h> 25 29 #include <scheduler.h> 26 #include <kmem.h>27 30 #include <errno.h> 28 #include < task.h>29 #include < spinlock.h>31 #include <printk.h> 32 #include <remote_spinlock.h> 30 33 31 int sys_thread_join (pthread_t tid, void **thread_return) 34 /////////////////////////////////////// 35 int sys_thread_join ( trdid_t trdid, 36 void ** exit_value ) 32 37 { 33 register struct task_s *task; 34 register struct thread_s *this; 35 register struct thread_s *target_th; 36 register uint_t state = 0; 37 void *retval; 38 int err; 38 xptr_t target_xp; 39 thread_t * target_ptr; 40 cxy_t target_cxy; 41 ltid_t target_ltid; 42 uint32_t flags; // target thread flags 43 intptr_t value; // value returned by target thread 44 paddr_t paddr; // required for vmm_v2p_translate() 39 45 40 this = current_thread; 41 task = this->task; 42 retval = 0; 46 thread_t * this = CURRENT_THREAD; 47 process_t * process = this->process; 43 48 44 if((tid > task->max_order) || 45 ((thread_return != NULL) && 46 (NOT_IN_USPACE((uint_t)thread_return + sizeof(void*))))) 49 // get target thread ltid and cxy 50 target_ltid = LTID_FROM_TRDID( trdid ); 51 target_cxy = CXY_FROM_TRDID( trdid ); 52 53 // check trdid argument 54 if( (target_ltid >= CONFIG_THREAD_MAX_PER_CLUSTER) || cluster_is_undefined( target_cxy ) ) 47 55 { 48 err = EINVAL; 49 goto fail_arg; 56 printk("\n[ERROR] in %s : illegal trdid argument\n", __FUNCTION__ ); 57 this->errno = EINVAL; 58 return -1; 50 59 } 51 60 52 /* try to write to userland address */ 53 if( thread_return)61 // check exit_value argument 62 if( (exit_value != NULL) && (vmm_v2p_translate( false , exit_value , &paddr ) != 0 ) ) 54 63 { 55 if((err = cpu_copy_to_uspace(thread_return, &retval, sizeof(void *)))) 56 goto fail_uspace_ret; 64 printk("\n[ERROR] in %s : illegal exit_value argument\n", __FUNCTION__ ); 65 this->errno = EINVAL; 66 return -1; 57 67 } 58 68 59 spinlock_lock(&task->th_lock); 60 target_th = task->th_tbl[tid]; 69 // check target thread != this thread 70 if( this->trdid == trdid ) 71 { 72 printk("\n[ERROR] in %s : this thread == target thread\n", __FUNCTION__ ); 73 this->errno = EDEADLK; 74 return -1; 75 } 61 76 62 if((target_th == NULL) || 63 (target_th->signature != THREAD_ID) || 64 (target_th->info.attr.key != tid)) 65 { 66 err = ESRCH; 67 goto fail_srch; 68 } 77 // get extended pointer on target thread 78 target_xp = thread_get_xptr( process->pid , trdid ); 69 79 70 if(target_th == this) 71 { 72 err = EDEADLK; 73 goto fail_deadlock; 74 } 80 if( target_xp == XPTR_NULL ) 81 { 82 printk("\n[ERROR] in %s : target thread not found\n", __FUNCTION__ ); 83 this->errno = ESRCH; 84 return -1; 85 } 75 86 76 if(!(thread_isJoinable(target_th))) 77 { 78 err = EINVAL; 79 goto fail_joinable; 80 } 81 82 spinlock_lock(&target_th->lock); 83 84 if(target_th->info.join != NULL) 85 { 86 spinlock_unlock(&target_th->lock); 87 err = EINVAL; 88 goto fail_joined; 89 } 87 // get cluster and local pointer on target thread 88 target_ptr = (thread_t *)GET_PTR( target_xp ); 90 89 91 // Get the exit code of the target thread 92 if ((state=wait_queue_isEmpty(&target_th->info.wait_queue))) 93 { 94 target_th->info.join = this; 95 wait_on(&target_th->info.wait_queue, WAIT_ANY); 96 spinlock_unlock(&target_th->lock); 97 spinlock_unlock_nosched(&task->th_lock); 98 sched_sleep(this); 99 retval = this->info.exit_value; 100 } 101 else 102 { 103 retval = target_th->info.exit_value; 104 wakeup_one(&target_th->info.wait_queue, WAIT_ANY); 105 spinlock_unlock(&target_th->lock); 106 spinlock_unlock(&task->th_lock); 107 } 90 // check target thread joinable 91 flags = hal_remote_lw( XPTR( target_cxy , &target_ptr->flags ) ); 92 if( flags & THREAD_FLAG_DETACHED ) 93 { 94 printk("\n[ERROR] in %s : target thread not joinable\n", __FUNCTION__ ); 95 this->errno = EINVAL; 96 return -1; 97 } 108 98 109 /* Probably will not fail */ 110 if(thread_return)111 112 if((err = cpu_copy_to_uspace(thread_return, &retval, sizeof(void *)))) 113 goto fail_uspace;114 99 // check kernel stack overflow 100 if( target_ptr->signature != THREAD_SIGNATURE ) 101 { 102 printk("\n[PANIC] in %s : kernel stack overflow\n", __FUNCTION__ ); 103 hal_core_sleep(); 104 } 115 105 116 return 0; 106 // wait target thread exit 107 while( 1 ) 108 { 109 // take the target thread lock protecting flags 110 remote_spinlock_lock( XPTR( target_cxy , &target_ptr->flags_lock ) ); 117 111 118 fail_joined: 119 fail_joinable: 120 fail_deadlock: 121 fail_srch: 122 spinlock_unlock(&task->th_lock); 112 // get the remote thread flags 113 flags = hal_remote_lw( XPTR( target_cxy , &target_ptr->flags ) ); 123 114 124 fail_uspace: 125 fail_uspace_ret: 126 fail_arg: 127 this->info.errno = err; 128 return err; 129 } 115 // check the EXIT flag 116 if( flags & THREAD_FLAG_EXIT ) // target made an exit 117 { 118 // unblock the target thread 119 thread_unblock( target_xp , THREAD_BLOCKED_EXIT ); 120 121 // release the target thread lock protecting flags 122 remote_spinlock_unlock( XPTR( target_cxy , &target_ptr->flags_lock ) ); 123 124 // exit while 125 break; 126 } 127 else // no exit done by target thread 128 { 129 // set the JOIN flag in target thread 130 hal_remote_atomic_or( XPTR( target_xp , &target_ptr->flags ) , 131 THREAD_BLOCKED_JOIN ); 132 133 // block this thread 134 thread_block( this , THREAD_BLOCKED_JOIN ); 135 136 // release the target thread lock protecting flags 137 remote_spinlock_unlock( XPTR( target_cxy , &target_ptr->flags_lock ) ); 138 139 // deschedule 140 sched_yield(); 141 } 142 } 143 144 // return exit_value from target thread descriptor 145 value = (intptr_t)hal_remote_lpt( XPTR( target_cxy , &target_ptr->exit_value ) ); 146 *exit_value = (void *)value; 147 return 0; 148 149 } // end sys_thread_join()
Note: See TracChangeset
for help on using the changeset viewer.