source: trunk/kernel/syscalls/sys_thread_create.c @ 624

Last change on this file since 624 was 624, checked in by alain, 6 years ago

Fix several bugs to use the instruction MMU in kernel mode
in replacement of the instruction address extension register,
and remove the "kentry" segment.

This version is running on the tsar_generic_iob" platform.

One interesting bug: the cp0_ebase defining the kernel entry point
(for interrupts, exceptions and syscalls) must be initialized
early in kernel_init(), because the VFS initialisation done by
kernel_ini() uses RPCs, and RPCs uses Inter-Processor-Interrup.

File size: 7.2 KB
RevLine 
[1]1/*
2 * sys_thread_create.c - creates a new user thread
[289]3 *
[624]4 * Author     Alain Greiner (2016,2017,2018,2019)
[1]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
[14]24#include <kernel_config.h>
[457]25#include <hal_kernel_types.h>
[23]26#include <hal_uspace.h>
[624]27#include <hal_vmm.h>
[1]28#include <printk.h>
29#include <errno.h>
30#include <core.h>
31#include <cluster.h>
32#include <list.h>
33#include <xlist.h>
34#include <thread.h>
35#include <scheduler.h>
36#include <kmem.h>
37#include <process.h>
38#include <dqdt.h>
[23]39#include <rpc.h>
[1]40
[506]41#include <syscalls.h>
[1]42
[566]43/////////////////////////////////////////////////////////
44int sys_thread_create( trdid_t               * trdid_ptr,
45                       struct pthread_attr_s * user_attr,
46                       void                  * start_func,
47                       void                  * start_args )
[1]48{
[407]49        pthread_attr_t   kern_attr;        // copy of pthread attributes in kernel space
[1]50        thread_t       * parent;           // pointer on thread executing the pthread_create
[566]51        xptr_t           parent_xp;        // extended pointer on calling thread
52    cxy_t            child_cxy;        // created child thread cluster identifier
[289]53        thread_t       * child_ptr;        // pointer on created child thread
54        xptr_t           child_xp;         // extended pointer on created thread
55        trdid_t          trdid;            // created thread identifier
56        process_t      * process;          // pointer on local process descriptor
[440]57        vseg_t         * vseg;             // required for user space checking
[289]58        error_t          error;
[1]59
[407]60        // get parent thead pointer, extended pointer, and process
[1]61        parent     = CURRENT_THREAD;
[289]62        parent_xp  = XPTR( local_cxy , parent );
[1]63        process    = parent->process;
64
[594]65#if (DEBUG_SYS_THREAD_CREATE || CONFIG_INSTRUMENTATION_SYSCALLS)
66uint64_t     tm_start = hal_get_cycles();
67#endif
68
[438]69#if DEBUG_SYS_THREAD_CREATE
[437]70tm_start = hal_get_cycles();
[438]71if( DEBUG_SYS_THREAD_CREATE < tm_start )
[594]72printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
[619]73__FUNCTION__, process->pid, parent->trdid, (uint32_t)tm_start );
[437]74#endif
75
[440]76    // check trdid buffer in user space
[566]77    error = vmm_get_vseg( process , (intptr_t)trdid_ptr , &vseg );
[440]78
79    if ( error )
80    {
81
82#if DEBUG_SYSCALLS_ERROR
[594]83printk("\n[ERROR] in %s : thread[%x,%x] / trdid buffer %x unmapped %x\n",
84__FUNCTION__, process->pid, parent->trdid, (intptr_t)trdid_ptr );
[624]85hal_vmm_display( process , false );
[440]86#endif
87                parent->errno = EINVAL;
88                return -1;
89    }
90
91        // check user_attr buffer in user space & copy to kernel space
[407]92    if( user_attr != NULL )
93    {
[440]94            error = vmm_get_vseg( process , (intptr_t)user_attr , &vseg );
[23]95
[407]96            if( error )
97            {
[437]98
[438]99#if DEBUG_SYSCALLS_ERROR
[594]100printk("\n[ERROR] in %s : thread[%x,%x] / user_attr buffer unmapped %x\n",
101__FUNCTION__, process->pid, parent->trdid, (intptr_t)user_attr );
[624]102hal_vmm_display( process , false );
[437]103#endif
[407]104                    parent->errno = EINVAL;
105                    return -1;
106            }
107       
108            hal_copy_from_uspace( &kern_attr , user_attr , sizeof(pthread_attr_t) );
109    }
[23]110
[289]111        // check start_func in user space
[440]112        error = vmm_get_vseg( process , (intptr_t)start_func , &vseg );
[23]113
[440]114    if( error )
115    {
[437]116
[438]117#if DEBUG_SYSCALLS_ERROR
[594]118printk("\n[ERROR] in %s : thread[%x,%x] / start_func unmapped %x\n",
119__FUNCTION__, process->pid, parent->trdid, (intptr_t)start_func );
[624]120hal_vmm_display( process , false );
[437]121#endif
[440]122        parent->errno = EINVAL;
123            return -1;
[1]124        }
125
[506]126        // check start_args buffer in user space
127        if( start_args != NULL )
[440]128    {
[506]129        error = vmm_get_vseg( process , (intptr_t)start_args , &vseg );
[1]130
[440]131            if( error )
132            {
[437]133
[438]134#if DEBUG_SYSCALLS_ERROR
[594]135printk("\n[ERROR] in %s : thread[%x,%x] / start_args buffer unmapped %x\n",
136__FUNCTION__, process->pid, parent->trdid, (intptr_t)start_args );
[624]137hal_vmm_display( process , false );
[437]138#endif
[440]139                    parent->errno = EINVAL;
140                    return -1;
141        }
[23]142        }
143
[566]144    // define attributes and child_cxy
[407]145    if( user_attr != NULL )                      // user defined attributes
146    {
[566]147            // check / get child_cxy
[407]148            if( kern_attr.attributes & PT_ATTR_CLUSTER_DEFINED )
149            {
150                    if( cluster_is_undefined( kern_attr.cxy ) )
151                    {
[437]152
[438]153#if DEBUG_SYSCALLS_ERROR
[594]154printk("\n[ERROR] in %s : thread[%x,%x] / illegal target cluster %x\n",
155__FUNCTION__, process->pid, parent->trdid, kern_attr.cxy );
[437]156#endif
[407]157                            parent->errno = EINVAL;
158                            return -1;
159            }
[566]160            child_cxy = kern_attr.cxy;
[289]161                }
[407]162        else
163        {
[566]164            child_cxy = dqdt_get_cluster_for_process();
[407]165        }
[289]166        }
[407]167        else                                        // set default attributes
[289]168        {
[407]169        kern_attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
[566]170        child_cxy           = dqdt_get_cluster_for_process();
[289]171        }
[1]172
[289]173        // create the thread, using a RPC if required
[407]174        // this returns "error", "child_ptr", and "child_xp"
[1]175
[566]176        if( child_cxy == local_cxy )                         // target cluster is local
[289]177        {
178                // create thread in local cluster
179                error = thread_user_create( process->pid,
180                                            start_func,
[506]181                                            start_args,
[407]182                                            &kern_attr,
[289]183                                            &child_ptr );
[1]184
[289]185                child_xp = XPTR( local_cxy , child_ptr );
186        }
187        else                                                 // target cluster is remote
188        {
[566]189                rpc_thread_user_create_client( child_cxy,
[289]190                                               process->pid,
191                                               start_func,
[506]192                                               start_args,
[407]193                                               &kern_attr,
[289]194                                               &child_xp,
195                                               &error );
[23]196
[289]197                child_ptr = (thread_t *)GET_PTR( child_xp );
198        }
[1]199
[289]200        // check successful thread creation
201        if( error )
202        {
[437]203
[438]204#if DEBUG_SYSCALLS_ERROR
[594]205printk("\n[ERROR] in %s : thread[%x,%x] cannot create new thread\n",
206__FUNCTION__ , process->pid, parent->trdid );
[437]207#endif
[440]208                parent->errno = ENOMEM;
209                return -1;
[289]210        }
[1]211
[289]212        // returns trdid to user space
[566]213        trdid = hal_remote_l32( XPTR( child_cxy , &child_ptr->trdid ) );
214        hal_copy_to_uspace( trdid_ptr , &trdid , sizeof(pthread_t) );
[1]215
[407]216    // activate new thread
217        thread_unblock( child_xp , THREAD_BLOCKED_GLOBAL );
218
219    hal_fence();
220
[594]221#if (DEBUG_SYS_THREAD_CREATE || CONFIG_INSTRUMENTATION_SYSCALLS)
222uint64_t     tm_end = hal_get_cycles();
223#endif
224
[438]225#if DEBUG_SYS_THREAD_CREATE
226if( DEBUG_SYS_THREAD_CREATE < tm_end )
[594]227printk("\n[%s] thread[%x,%x] created thread %x / cycle %d\n",
228__FUNCTION__, process->pid, parent->trdid, child_ptr->trdid, (uint32_t)tm_end );
[437]229#endif
[1]230
[594]231#if CONFIG_INSTRUMENTATION_SYSCALLS
232hal_atomic_add( &syscalls_cumul_cost[SYS_THREAD_CREATE] , tm_end - tm_start );
233hal_atomic_add( &syscalls_occurences[SYS_THREAD_CREATE] , 1 );
234#endif
235
[1]236        return 0;
237
[407]238}  // end sys_thread_create()
239
Note: See TracBrowser for help on using the repository browser.