Ignore:
Timestamp:
Jun 18, 2017, 10:06:41 PM (5 years ago)
Author:
alain
Message:

Introduce syscalls.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/syscalls/sys_thread_join.c

    r1 r23  
    11/*
    2  * kern/sys_thread_join.c - passive wait on the end of a given thread
     2 * sys_thread_join.c - passive wait on the end of a given thread.
    33 *
    4  * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
     4 * Authors    Alain Greiner (2016,2017)
     5 *
    56 * Copyright (c) 2011,2012 UPMC Sorbonne Universites
    67 *
    7  * This file is part of ALMOS-kernel.
     8 * This file is part of ALMOS-MKH.
    89 *
    9  * ALMOS-kernel is free software; you can redistribute it and/or modify it
     10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
    1011 * under the terms of the GNU General Public License as published by
    1112 * the Free Software Foundation; version 2.0 of the License.
    1213 *
    13  * ALMOS-kernel is distributed in the hope that it will be useful, but
     14 * ALMOS-MKH is distributed in the hope that it will be useful, but
    1415 * WITHOUT ANY WARRANTY; without even the implied warranty of
    1516 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     
    1718 *
    1819 * 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,
    2021 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
    2122 */
    2223
    23 #include <list.h>
     24#include <hal_types.h>
     25#include <hal_remote.h>
     26#include <hal_special.h>
    2427#include <thread.h>
     28#include <vmm.h>
    2529#include <scheduler.h>
    26 #include <kmem.h>
    2730#include <errno.h>
    28 #include <task.h>
    29 #include <spinlock.h>
     31#include <printk.h>
     32#include <remote_spinlock.h>
    3033
    31 int sys_thread_join (pthread_t tid, void **thread_return)
     34///////////////////////////////////////
     35int sys_thread_join ( trdid_t    trdid,
     36                      void    ** exit_value )
    3237{
    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()
    3945
    40         this   = current_thread;
    41         task   = this->task;
    42         retval = 0;
     46        thread_t  * this    = CURRENT_THREAD;
     47    process_t * process = this->process;
    4348
    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 ) ) 
    4755        {
    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;
    5059        }
    5160
    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 ) )
    5463        {
    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;
    5767        }
    5868
    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    }
    6176
    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 );
    6979
    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    }
    7586
    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 );
    9089
    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    }
    10898
    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    }
    115105
    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 ) );
    117111
    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 ) );
    123114
    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.