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

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