/* * sys_thread_create.c - creates a new user thread * * 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 #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////////////////// // This function implements the pthread_create system call ////////////////////////////////////////////////////////////////////////////////////////// int sys_thread_create ( thread_t * new_thread, // [out] argument pthread_attr_t * user_attr, // [in] argument void * start_func, // [in] argument void * start_args ) // [in] argument { pthread_attr_t attr; // copy of pthread attributes in kernel space thread_t * parent; // pointer on thread executing the pthread_create xptr_t xp_parent; // extended pointer on created thread thread_t * child; // pointer on created child thread xptr_t xp_child; // extended pointer on created thread trdid_t trdid; // created thread identifier process_t * process; // pointer on local process descriptor error_t error; uint32_t tm_start; uint32_t tm_end; tm_start = hal_time_stamp(); // get parent thead pointer, extended pointer, and process pointer parent = CURRENT_THREAD; xp_parent = XPTR( local_cxy , parent ); process = parent->process; // check user_attr & start_func arguments if( user_attr == NULL ) { printk("\n[ERROR] in %s : user_attr is NULL\n", __FUNCTION__ ); return EINVAL; } if( start_func== NULL ) { printk("\n[ERROR] in %s : start_func is NULL\n", __FUNCTION__ ); return EINVAL; } // copy user_attr structure to kernel space hal_copy_from_uspace( &attr , user_attr , sizeof(pthread_attr_t) ); // check/set "cxy" attribute if( attr.flags & PT_FLAG_CLUSTER_DEFINED ) { if( cluster_is_undefined( attr.cxy ) ) { printk("\n[ERROR] in %s : illegal target cluster = %x\n", __FUNCTION__ , attr.cxy ); return = EINVAL; } } else { attr.cxy = dqdt_get_cluster_for_process(); } // set "pid", "start_func" & "start_args" attributes attr.pid = process->pid; attr.start_func = start_func; attr.start_args = start_args; // create the thread, using a RPC if required // this returns "error", "child", and "xp_child" if( attr.cxy == local_cxy ) // target cluster is local { // allocate a stack from local VMM vseg_t * vseg = vmm_create_vseg( process, 0, 0, VSEG_TYPE_STACK, local_cxy ); if( vseg == NULL ) { printk("\n[ERROR] in %s for : cannot create stack vseg\n", __FUNCTION__ ); return = EINVAL; } // create thread in local cluster error = thread_user_create( &child, &attr, vseg->min, vseg->max - vseg->min ); xp_child = XPTR( local_cxy , thread ); } else // target cluster is remote { rpc_thread_user_create( attr.cxy , &attr , &error , &xp_child ); child = (thread_t *)GET_PTR( xp_child ); } // check successful thread creation if( error ) { printk("\n[ERROR] in %s : cannot create thread\n", __FUNCTION__ ); return ENOMEM; } // returns trdid to user space trdid = hal_remote_lw( XPTR( attr.cxy , &child->trdid ) ); hal_copy_to_uspace( new_thread , &trdid , sizeof(pthread_t) ); // register new-thread in parent-thread children list if required if( attr.flags & PT_FLAG_DETACH == 0 ) thread_child_parent_link( xp_parent , xp_child ); tm_end = hal_time_stamp(); thread_dmsg("\n[INFO] %s created thread %x for process %x in cluster %x\n" " start_cycle = %d / end_cycle = %d\n", trdid , process->pid , attr.cxy , tm_start , tm_end ); return 0; } // end sys_thread_create()