Changeset 662 for trunk/kernel/kern


Ignore:
Timestamp:
Oct 10, 2020, 4:50:41 PM (4 years ago)
Author:
alain
Message:

Introduce the ksocket.h & ksocket.c files in kernel/kern.

Location:
trunk/kernel/kern
Files:
9 edited
2 moved

Legend:

Unmodified
Added
Removed
  • trunk/kernel/kern/chdev.c

    r657 r662  
    301301    server = CURRENT_THREAD;
    302302
     303#if( DEBUG_CHDEV_SERVER_RX || DEBUG_CHDEV_SERVER_TX )
     304uint32_t rx_cycle = (uint32_t)hal_get_cycles();
     305if( (chdev->is_rx) && (DEBUG_CHDEV_SERVER_RX < rx_cycle) )
     306printk("\n[%s] RX server thread[%x,%x] enter / channel %d / cycle %d\n",
     307__FUNCTION__ , server->process->pid, server->trdid, chdev->channel, rx_cycle );
     308#endif
     309
     310#if DEBUG_CHDEV_SERVER_TX
     311uint32_t tx_cycle = (uint32_t)hal_get_cycles();
     312if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) )
     313printk("\n[%s] TX server thread[%x,%x] enter / channel %d / cycle %d\n",
     314__FUNCTION__ , server->process->pid, server->trdid, chdev->channel, tx_cycle );
     315#endif
     316
    303317    // build extended pointer on root & lock of client threads queue
    304318    root_xp = XPTR( local_cxy , &chdev->wait_root );
     
    309323    while( 1 )
    310324    {
    311 
    312 #if( DEBUG_CHDEV_SERVER_RX || DEBUG_CHDEV_SERVER_TX )
    313 uint32_t rx_cycle = (uint32_t)hal_get_cycles();
    314 if( (chdev->is_rx) && (DEBUG_CHDEV_SERVER_RX < rx_cycle) )
    315 printk("\n[%s] server thread[%x,%x] check TXT_RX channel %d / cycle %d\n",
    316 __FUNCTION__ , server->process->pid, server->trdid, chdev->channel, rx_cycle );
    317 #endif
    318 
    319 #if DEBUG_CHDEV_SERVER_TX
    320 uint32_t tx_cycle = (uint32_t)hal_get_cycles();
    321 if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) )
    322 printk("\n[%s] thread[%x,%x] check TXT_TX channel %d / cycle %d\n",
    323 __FUNCTION__ , server->process->pid, server->trdid, chdev->channel, tx_cycle );
    324 #endif
    325 
    326325        // check server thread can yield
    327326        thread_assert_can_yield( server , __FUNCTION__ );
     
    331330
    332331        // check waiting queue state
    333         if( xlist_is_empty( root_xp ) ) // waiting queue empty
     332        if( xlist_is_empty( root_xp ) )                      // waiting queue empty
    334333        {
    335334            // release lock protecting the waiting queue
     
    339338rx_cycle = (uint32_t)hal_get_cycles();
    340339if( (chdev->is_rx) && (DEBUG_CHDEV_SERVER_RX < rx_cycle) )
    341 printk("\n[%s] server thread[%x,%x] found RX queue empty => blocks / cycle %d\n",
     340printk("\n[%s] RX server thread[%x,%x] blocks & deschedules / cycle %d\n",
    342341__FUNCTION__ , server->process->pid, server->trdid, rx_cycle );
    343342#endif
     
    346345tx_cycle = (uint32_t)hal_get_cycles();
    347346if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) )
    348 printk("\n[%s] server thread[%x,%x] found TX queue empty => blocks / cycle %d\n",
     347printk("\n[%s] TX server thread[%x,%x] blocks & deschedules / cycle %d\n",
    349348__FUNCTION__ , server->process->pid, server->trdid, tx_cycle );
    350349#endif
    351             // block
     350            // block and deschedule
    352351            thread_block( XPTR( local_cxy , server ) , THREAD_BLOCKED_CLIENT );
    353 
    354             // deschedule
    355             sched_yield("I/O queue empty");
     352            sched_yield("clients queue empty");
     353
     354#if DEBUG_CHDEV_SERVER_RX
     355rx_cycle = (uint32_t)hal_get_cycles();
     356if( (chdev->is_rx) && (DEBUG_CHDEV_SERVER_RX < rx_cycle) )
     357printk("\n[%s] RX server thread[%x,%x] resumes / cycle %d\n",
     358__FUNCTION__ , server->process->pid, server->trdid, rx_cycle );
     359#endif
     360
     361#if DEBUG_CHDEV_SERVER_TX
     362tx_cycle = (uint32_t)hal_get_cycles();
     363if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) )
     364printk("\n[%s] TX server thread[%x,%x] resumes / cycle %d\n",
     365__FUNCTION__ , server->process->pid, server->trdid, tx_cycle );
     366#endif
     367
    356368        }
    357         else                            // waiting queue not empty
     369        else                                               // waiting queue not empty
    358370        {
    359371            // get pointers on first client thread
     
    414426if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) )
    415427printk("\n[%s] thread[%x,%x] completes command for client thread[%x,%x] / cycle %d\n",
    416 __FUNCTION__, server->process->pid, server->trdid, client_pid, client_trdid, tX_cycle );
     428__FUNCTION__, server->process->pid, server->trdid, client_pid, client_trdid, tx_cycle );
    417429#endif
    418430
  • trunk/kernel/kern/chdev.h

    r657 r662  
    110110
    111111/******************************************************************************************
    112  * This structure defines a chdev descriptor.
     112 * This structure defines a chdev (channel device) descriptor.
    113113 * This structure is NOT replicated, and can be located in any cluster.
    114  * One kernel thread, in charge of handling the commands registered in the waiting queue
    115  * of client threads is associated to each chdev descriptor (not for ICU, PIC, IOB).
     114 * One server thread is in charge of handling the commands registered in the queue
     115 * of clients associated to each chdev descriptor.
     116 *
    116117 * For each device type ***, the specific extension is defined in the "dev_***.h" file.
    117118 *
    118119 * NOTE . For most chdevs, the busylock is used to protect the waiting queue changes,
    119  *        when a thread register in this queue, or is removed after service.
     120 *        when a client registers in this queue, or is removed after service.
    120121 *      . This busylock is also used to protect direct access to the shared
    121122 *        kernel TXT0 terminal, that does not use the waiting queue.
    122  *      . For the NIC chdevs it is also used to protect registration (or removal) of a
    123  *        socket in the list of attached sockets rooted in NIC device extension.
     123 *      . For mostd chdevs, the client waiting queue is an xlist of threads, but it is
     124 *        a list of sockets for the NIC chdevs. It is unused for ICU, PIC, and IOB.
    124125 *****************************************************************************************/
    125126
     
    142143    uint32_t             irq_id;      /*! associated IRQ index in local ICU              */
    143144
    144         xlist_entry_t        wait_root;   /*! root of client threads waiting queue           */
     145        xlist_entry_t        wait_root;   /*! root of clients waiting queue                  */
    145146    remote_busylock_t    wait_lock;   /*! lock protecting waiting queue                  */
     147    uint32_t             wait_nr;     /*! number of registered clients (NIC only)        */
    146148
    147149    union
  • trunk/kernel/kern/kernel_init.c

    r657 r662  
    4040#include <thread.h>
    4141#include <scheduler.h>
     42#include <ksocket.h>
    4243#include <kmem.h>
    4344#include <cluster.h>
     
    130131char * lock_type_str[] =
    131132{
    132     "unused_0",              //  0
     133    "unused_0",              //  0   must be unused to help debug
    133134
    134135    "CLUSTER_KCM",           //  1
     
    153154    "PROCESS_CWD",           // 19
    154155    "BARRIER_STATE",         // 20
    155 
    156     "CLUSTER_PREFTBL",       // 21
    157 
    158     "PPM_DIRTY",             // 22
    159     "CLUSTER_LOCALS",        // 23
    160     "CLUSTER_COPIES",        // 24
    161     "PROCESS_CHILDREN",      // 25
    162     "PROCESS_USERSYNC",      // 26
    163     "PROCESS_FDARRAY",       // 27
    164     "PROCESS_DIR",           // 28
    165     "VMM_VSL",               // 29
    166 
    167     "PROCESS_THTBL",         // 30
    168 
    169     "MAPPER_STATE",          // 31
    170     "VFS_SIZE",              // 32
    171     "VFS_FILE",              // 33
    172     "VFS_MAIN",              // 34
    173     "FATFS_FAT",             // 35
    174     "FBF_WINDOWS",           // 36
     156    "LISTEN_SOCKET",         // 21
     157
     158    "CLUSTER_PREFTBL",       // 22
     159
     160    "SOCKET_STATE",          // 23
     161    "PPM_DIRTY",             // 24
     162    "CLUSTER_LOCALS",        // 25
     163    "CLUSTER_COPIES",        // 26
     164    "PROCESS_CHILDREN",      // 27
     165    "PROCESS_USERSYNC",      // 28
     166    "PROCESS_FDARRAY",       // 29
     167    "PROCESS_DIR",           // 30
     168    "VMM_VSL",               // 31
     169
     170    "PROCESS_THTBL",         // 32
     171
     172    "MAPPER_STATE",          // 33
     173    "VFS_SIZE",              // 34
     174    "VFS_FILE",              // 35
     175    "VFS_MAIN",              // 36
     176    "FATFS_FAT",             // 37
     177    "FBF_WINDOWS",           // 38
    175178};       
    176179
    177 // debug variables to analyse the sys_read() and sys_write() syscalls timing
     180// debug variables to analyse the sys_read() syscalls timing
    178181
    179182#if DEBUG_SYS_READ
     
    200203#endif
    201204
    202 // these debug variables are used to analyse the sys_write() syscall timing
     205// debug variables to analyse the sys_write() syscall timing
    203206
    204207#if DEBUG_SYS_WRITE   
     
    14881491                   " - core descriptor    : %d bytes\n"
    14891492                   " - scheduler          : %d bytes\n"
     1493                   " - socket             : %d bytes\n"
    14901494                   " - rpc fifo           : %d bytes\n"
    14911495                   " - page descriptor    : %d bytes\n"
     
    15151519                   sizeof( core_t             ),
    15161520                   sizeof( scheduler_t        ),
     1521                   sizeof( socket_t           ),
    15171522                   sizeof( remote_fifo_t      ),
    15181523                   sizeof( page_t             ),
  • trunk/kernel/kern/ksocket.c

    r657 r662  
    11/*
    2  * socket.h - socket descriptor and API definition.
    3  * 
    4  * Authors  Alain Greiner    (2016,2017,2018,2019,2020)
     2 * ksocket.c - kernel socket API implementation.
     3 *
     4 * Authors  Alain Greiner   (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
    77 *
    8  * This file is part of ALMOS-MKH
     8 * This file is part of ALMOS-MKH.
    99 *
    1010 * ALMOS-MKH is free software; you can redistribute it and/or modify it
     
    1818 *
    1919 * 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,
     20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
    2121 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
    2222 */
    2323
    24 #ifndef _SOCKET_H_
    25 #define _SOCKET_H_
    26 
    2724#include <kernel_config.h>
    2825#include <hal_kernel_types.h>
    29 #include <xlist.h>
     26#include <hal_remote.h>
     27#include <hal_uspace.h>
     28#include <shared_socket.h>
     29#include <process.h>
    3030#include <remote_buf.h>
    31 #include <remote_busylock.h>
    32 
    33 /****************************************************************************************
    34  * This defines the three commands that can be requested by a client thread to
    35  * a TX server thread. These commands are registered in the socket descriptor.
    36  ****************************************************************************************/
    37 
    38 typedef enum sock_cmd_e
    39 {
    40     SOCKET_TX_CONNECT = 20,   /*! request 3 steps handshake (TCP socket only)           */
    41     SOCKET_TX_SEND    = 21,   /*! request to send data      (TCP or UDP socket)         */
    42     SOCKET_TX_CLOSE   = 22,   /*! request 3 steps handshake (TCP socket only)           */
     31#include <bits.h>
     32#include <printk.h>
     33#include <kmem.h>
     34#include <thread.h>
     35#include <vfs.h>
     36#include <ksocket.h>
     37#include <dev_nic.h>
     38
     39//////////////////////////////////////////////////////////////////////////////////////
     40// Extern global variables
     41//////////////////////////////////////////////////////////////////////////////////////
     42
     43extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
     44
     45///////////////////////////////////////////
     46char * socket_domain_str( uint32_t domain )
     47{
     48    switch( domain )
     49    {
     50        case AF_INET         : return "INET";
     51        case AF_LOCAL        : return "LOCAL";
     52
     53        default              : return "undefined";
     54    }
    4355}
    44 sock_cmd_t;
    45 
    46 /*****************************************************************************************
    47  * This structure defines a socket descriptor. In order to parallelize the transfers,
    48  * the set of all registered sockets is split in several subsets.
    49  * The number of subsets is the number of  NIC channels.
    50  * The distribution key is computed from the (remote_addr/remote_port) couple.
    51  * This computation is done by the NIC hardware for RX packets,
    52  * and by the dev_nic_connect() function for the TX packets.
    53  *
    54  * A socket is attached to the NIC_TX[channel] & NIC_RX[channel] chdevs.
    55  * Each socket descriptor allows the TX and TX server threads to access various buffers:
    56  * - the user "send" buffer contains the data to be send by the TX server thread.
    57  * - the kernel "receive" buffer contains the data received by the RX server thread.
    58  * - the kernel "r2t" buffer allows the RX server thread to make direct requests
    59  *   to the associated TX server (to implement the TCP 3 steps handshake).
    60  *
    61  * The synchronisation mechanism between the clients threads and the servers threads
    62  * is different for TX and RX transfers:
    63  *
    64  * 1) For a TX transfer, it can exist only one client thread for a given socket,
    65  *    the transfer is always initiated by the local process, and all TX commands
    66  *    (CONNECT/SEND/CLOSE) are blocking for the client thread. The user buffer is
    67  *    used by TCP to handle retransmissions when required.in case of re
    68  *    The client thread registers the command in the thread descriptor, registers itself
    69  *    in the socket descriptor, unblocks the TX server thread from the BLOCKED_CLIENT
    70  *    condition, blocks itself on the BLOCKED_IO condition, and deschedules.
    71  *    When the command is completed, the TX server thread unblocks the client thread.
    72  *    The TX server blocks itself on the BLOCKED_CLIENT condition, when there is no
    73  *    pending commands and the R2T queue is empty. It is unblocked when a client
    74  *    register a new command, or when the TX server thread register a mew request
    75  *    in the R2T queue.
    76  *    The tx_valid flip-flop is SET by the client thread to signal a valid command.
    77  *    It is RESET by the server thread when the command is completed: For a SEND,
    78  *    all bytes have been sent (UDP) or acknowledged (TCP).
    79  *
    80  * 2) For an RX transfer, it can exist only one client thread for a given socket,
    81  *    but the transfer is initiated by the remote process, and the  RECV command
    82  *    is not really blocking: the data can arrive before the local RECV command is
    83  *    executed, and the server thread does not wait to receive all requested data
    84  *    to deliver data to client thread. Therefore each socket contains a receive
    85  *    buffer (rx_buf) handled as a single-writer/single-reader fifo.
    86  *    The client thread consumes data from the rx_buf when possible. It blocks on the
    87  *    BLOCKED_IO condition and deschedules when the rx_buf is empty.
    88  *    It is unblocked by the RX server thread when new data is available in the rx_buf.
    89  *    The RX server blocks itself on the BLOCKED_ISR condition When the NIC_RX packets
    90  *    queue is empty. It is unblocked by the hardware when new packets are available.
    91  *
    92  * Note : the socket domains and types are defined in the "shared_socket.h" file.
    93  ****************************************************************************************/
    94 
    95 typedef enum udp_socket_state_e
    96 {
    97     UDP_STATE_UNBOUND   = 0,
    98     UDP_STATE_BOUND     = 1,
    99     UDP_STATE_CONNECT   = 2,
     56   
     57///////////////////////////////////////
     58char * socket_type_str( uint32_t type )
     59{
     60    switch( type )
     61    {
     62        case SOCK_DGRAM         : return "UDP";
     63        case SOCK_STREAM        : return "TCP";
     64
     65        default                 : return "undefined";
     66    }
    10067}
    101 udp_socket_state_t;
    102 
    103 typedef enum tcp_socket_state_e
    104 {
    105     TCP_STATE_UNBOUND    = 10,
    106     TCP_STATE_BOUND      = 11,
    107     TCP_STATE_LISTEN     = 12,
    108     TCP_STATE_SYN_SENT   = 13,
    109     TCP_STATE_SYN_RCVD   = 14,
    110     TCP_STATE_ESTAB      = 15,
    111     TCP_STATE_FIN_WAIT1  = 16,
    112     TCP_STATE_FIN_WAIT2  = 17,
    113     TCP_STATE_CLOSING    = 18,
    114     TCP_STATE_TIME_WAIT  = 19,
    115     TCP_STATE_CLOSE_WAIT = 20,
    116     TCP_STATE_LAST_ACK   = 21,
     68   
     69/////////////////////////////////////////
     70char * socket_state_str( uint32_t state )
     71{
     72    switch( state )
     73    {
     74        case UDP_STATE_UNBOUND    : return "UDP_UNBOUND";
     75        case UDP_STATE_BOUND      : return "UDP_BOUND";
     76        case UDP_STATE_ESTAB      : return "UDP_ESTAB";
     77
     78        case TCP_STATE_UNBOUND    : return "TCP_UNBOUND";
     79        case TCP_STATE_BOUND      : return "TCP_BOUND";
     80        case TCP_STATE_LISTEN     : return "TCP_LISTEN";
     81        case TCP_STATE_SYN_SENT   : return "TCP_SYN_SENT";
     82        case TCP_STATE_SYN_RCVD   : return "TCP_SYN_RCVD";
     83        case TCP_STATE_ESTAB      : return "TCP_ESTAB";
     84        case TCP_STATE_FIN_WAIT1  : return "TCP_FIN_WAIT1";
     85        case TCP_STATE_FIN_WAIT2  : return "TCP_FIN_WAIT2";
     86        case TCP_STATE_CLOSING    : return "TCP_CLOSING";
     87        case TCP_STATE_TIME_WAIT  : return "TCP_TIME_WAIT";
     88        case TCP_STATE_CLOSE_WAIT : return "TCP_CLOSE_WAIT";
     89        case TCP_STATE_LAST_ACK   : return "TCP_LAST_ACK";
     90        case TCP_STATE_CLOSED     : return "TCP_CLOSED";
     91
     92        default                   : return "undefined";
     93    }
    11794}
    118 tcp_socket_state_t;
    119 
    120 typedef struct socket_s
    121 {
    122     remote_busylock_t lock;          /*! lock protecting socket state                  */
    123     uint32_t          domain;        /*! domain : AF_LOCAL / AF_INET                   */
    124     uint32_t          type;          /*! type : SOCK_DGRAM / SOCK_STREAM               */
    125     pid_t             pid;           /*! owner process identifier                      */
    126     uint32_t          state;         /*! see above                                     */
    127     uint32_t          local_addr;    /*! local  socket IP address                      */
    128     uint32_t          remote_addr;   /*! remote socket IP address                      */
    129     uint32_t          local_port;    /*! local  socket port number                     */
    130     uint32_t          remote_port;   /*! remote socket port number                     */
    131     uint32_t          nic_channel;   /*! derived from (remote_addr,remote_port)        */
    132 
    133     xlist_entry_t     tx_list;       /*! sockets attached to same NIC_TX chdev         */
    134     xptr_t            tx_client;     /*! extended pointer on TX client thread          */
    135     sock_cmd_t        tx_cmd;        /*! command type (CONNECT/SEND/CLOSE)             */
    136     uint8_t         * tx_buf;        /*! pointer on user buffer in user space          */
    137     uint32_t          tx_len;        /*! number of bytes to be sent in command         */
    138     uint32_t          tx_todo;       /*! number of bytes not yet sent                  */
    139     uint32_t          tx_error;      /*! signal a TX command error                     */
    140 
    141     xlist_entry_t     rx_list;       /*! sockets attached to same NIC_RX chdev         */
    142     xptr_t            rx_client;     /*! extended pointer on RX client thread          */
    143     remote_buf_t      rx_buf;        /*! embedded receive buffer descriptor            */
    144 
    145     remote_buf_t      r2tq;          /*! RX_to_TX requests queue descriptor            */
    146 
    147     remote_buf_t      crqq;          /*! connection requests queue descriptor          */         
    148     /* the following fields defines the TCB used for a TCP connection                  */
    149 
    150     uint32_t          tx_una;        /*! first unack byte in TX_data stream            */
    151     uint32_t          tx_nxt;        /*! next byte to send in TX_data stream           */
    152     uint32_t          tx_wnd;        /*! number of acceptable bytes in TX_data stream  */
    153 
    154     uint32_t          rx_nxt;        /*! next expected byte in RX_data stream          */
    155     uint32_t          rx_wnd;        /*! number of acceptable bytes in RX_data stream  */
    156     uint32_t          rx_irs;        /*! initial sequence number in RX_data stream     */
     95
     96///////////////////////////////////////////
     97char * socket_cmd_type_str( uint32_t type )
     98{
     99    switch( type )
     100    {
     101        case CMD_TX_CONNECT  : return "TX_CONNECT";
     102        case CMD_TX_ACCEPT   : return "TX_ACCEPT";
     103        case CMD_TX_CLOSE    : return "TX_CLOSE";
     104        case CMD_TX_SEND     : return "TX_SEND";
     105
     106        case CMD_RX_ACCEPT   : return "RX_ACCEPT";
     107        case CMD_RX_RECV     : return "RX_RECV";
     108       
     109        default                 : return "undefined";
     110    }
    157111}
    158 socket_t;
    159 
    160 /****************************************************************************************
    161  * This function returns a printable string for a client_to_tx_server command type.
    162  ****************************************************************************************
    163  * type   :  SOCKET_TX_CONNECT / SOCKET_TX_SEND / SOCKET_TX_CLOSE
    164  ***************************************************************************************/
    165 char * socket_cmd_str( uint32_t type );
    166 
    167 /****************************************************************************************
    168  * This function returns a printable string for an UDP or TCP socket state.
    169  ****************************************************************************************
    170  * state  :  UDP_STATE_*** / TCP_STATE***
    171  ***************************************************************************************/
    172 char * socket_state_str( uint32_t state );
    173 
    174 /****************************************************************************************
    175  * This function allocates memory in the cluster defined by the <cxy> argument for a
    176  * socket descriptor defined by the <domain> and <type> aruments, for the associated
    177  * file descriptor, and for the various kernel buffers descriptors contained in the
    178  * socket descriptor : "rx_buf" (receive buffer), "r2tq" (RX to RX requests queue), and
    179  * "crqq" (connect requests queue). It initialises the socket desccriptor static fields,
    180  * (other than local_addr, local_port, remote_addr, remote_port).
    181  * It registers the file descriptor in the reference process fd_array[], set the socket
    182  * the socket state to UNBOUND, and returns the file identifier in the <fdid> argument.
    183  ****************************************************************************************
    184  * @ cxy     : [in]  target cluster identifier.
    185  * @ domain  : [in]  socket protocol family (must be AF_INET).
    186  * @ type    : [in]  socket type (SOCK_DGRAM / SOCK_STREAM).
    187  * @ socket  : [out] buffer for a local pointer on created socket.
    188  * @ fdid    : [out] buffer for file identifier.
    189  * @ return 0 if success / return -1 if failure (no memory).
    190  ***************************************************************************************/
    191 error_t socket_create( cxy_t              cxy,
    192                        uint32_t           domain,
    193                        uint32_t           type,
    194                        struct socket_s ** socket,
    195                        uint32_t         * fdid );
    196                        
    197 /****************************************************************************************
    198  * This functions releases all memory allocated to a socket identified by the <fdid>
    199  * argument. This include the file descriptor, the socket descriptor, and all buffers
    200  * referenced by the socket descriptor.
    201  ****************************************************************************************
    202  * @ fdid   : [in]  file descriptor index.
    203  ***************************************************************************************/
    204 void socket_destroy( uint32_t fdid );
    205 
    206 /****************************************************************************************
    207  * This functions registers the socket defined by the <socket_xp> argument into the
    208  * lists of sockets attached to the NIC_TX and NIC_TX chdevs identified by the
    209  * <nic_channel> argument.
    210  ****************************************************************************************
    211  * @ socket_xp   : [in]  extended pointer on socket descriptor
    212  * @ nic_channel : [in]  NIC channel index.
    213  ***************************************************************************************/
    214 void socket_link_to_servers( xptr_t    socket_xp,
    215                              uint32_t  nic_channel );
     112   
     113///////////////////////////////////////////
     114char * socket_cmd_sts_str( uint32_t sts )
     115{
     116    switch( sts )
     117    {
     118        case CMD_STS_SUCCESS  : return "TX_CONNECT";
     119        case CMD_STS_EOF      : return "EOF";
     120        case CMD_STS_RST      : return "RST";
     121        case CMD_STS_BADACK   : return "BADACK";
     122        case CMD_STS_BADSTATE : return "BADSTATE";
     123        case CMD_STS_BADCMD   : return "BADCMD";
     124       
     125        default               : return "undefined";
     126    }
     127}
     128
     129/////////////////////////////////////////////////////////////////////////////////////////
     130// This static function registers the socket defined by the <socket_xp> argument into
     131// the lists of sockets attached to the relevant NIC_TX and NIC_TX chdevs identified
     132// by the <channel> argument, and update the channel field in socket descriptor.
     133/////////////////////////////////////////////////////////////////////////////////////////
     134// @ socket_xp   : [in]  extended pointer on socket descriptor.
     135// @ channel     : [in]  NIC channel index.
     136/////////////////////////////////////////////////////////////////////////////////////////
     137static void socket_link_to_servers( xptr_t   socket_xp,
     138                                    uint32_t channel )
     139{
     140    cxy_t      socket_cxy = GET_CXY( socket_xp );
     141    socket_t * socket_ptr = GET_PTR( socket_xp );
     142
     143#if DEBUG_SOCKET_LINK
     144thread_t  * this        = CURRENT_THREAD;
     145process_t * process     = this->process;
     146pid_t       socket_pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     147fdid_t      socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     148uint32_t   cycle        = (uint32_t)hal_get_cycles();
     149if( DEBUG_SOCKET_LINK < cycle )
     150printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / cycle %d\n",
     151__FUNCTION__, process->pid, this->trdid, socket_pid, socket_fdid, cycle );
     152#endif
     153
     154    // get pointers on NIC_TX[channel] chdev
     155    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[channel];
     156    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
     157    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
     158
     159    // build various TX extended pointers
     160    xptr_t    tx_root_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_root );
     161    xptr_t    tx_lock_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_lock );
     162    xptr_t    tx_list_xp = XPTR( socket_cxy   , &socket_ptr->tx_list );
     163
     164    // get pointers on NIC_RX[channel] chdev
     165    xptr_t    rx_chdev_xp  = chdev_dir.nic_rx[channel];
     166    chdev_t * rx_chdev_ptr = GET_PTR( rx_chdev_xp );
     167    cxy_t     rx_chdev_cxy = GET_CXY( rx_chdev_xp );
     168
     169    // build various RX extended pointers
     170    xptr_t    rx_root_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_root );
     171    xptr_t    rx_lock_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_lock );
     172    xptr_t    rx_list_xp = XPTR( socket_cxy   , &socket_ptr->rx_list );
     173
     174    // register socket in the NIC_TX[channel] chdev clients queue
     175    remote_busylock_acquire( tx_lock_xp );
     176    xlist_add_last( tx_root_xp , tx_list_xp );
     177    remote_busylock_release( tx_lock_xp );
     178
     179    // register socket in the NIC_RX[channel] chdev clients queue
     180    remote_busylock_acquire( rx_lock_xp );
     181    xlist_add_last( rx_root_xp , rx_list_xp );
     182    remote_busylock_release( rx_lock_xp );
     183
     184#if DEBUG_SOCKET_LINK
     185cycle = (uint32_t)hal_get_cycles();
     186if( DEBUG_SOCKET_LINK < cycle )
     187printk("\n[%s] thread[%x,%x] linked socket[%x,%d] to channel %d / cycle %d\n",
     188__FUNCTION__, process->pid, this->trdid, process->pid, socket_pid, socket_fdid, channel, cycle );
     189#endif
     190
     191}  // end socket_link_to_servers()
     192
     193/////////////////////////////////////////////////////////////////////////////////////////
     194// This function removes the socket defined by the <socket_xp> argument from the
     195// lists of sockets attached to the relevant NIC_TX and NIC_TX chdevs.
     196/////////////////////////////////////////////////////////////////////////////////////////
     197// @ socket_xp   : [in]  extended pointer on socket descriptor
     198/////////////////////////////////////////////////////////////////////////////////////////
     199static void socket_unlink_from_servers( xptr_t socket_xp )
     200{
     201    cxy_t      socket_cxy = GET_CXY( socket_xp );
     202    socket_t * socket_ptr = GET_PTR( socket_xp );
     203
     204#if DEBUG_SOCKET_LINK
     205thread_t  * this        = CURRENT_THREAD;
     206process_t * process     = this->process;
     207pid_t       socket_pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     208fdid_t      socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     209uint32_t   cycle        = (uint32_t)hal_get_cycles();
     210if( DEBUG_SOCKET_LINK < cycle )
     211printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / cycle %d\n",
     212__FUNCTION__, process->pid, this->trdid, socket_pid, socket_fdid, cycle );
     213#endif
     214
     215    // get NIC channel
     216    uint32_t channel = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->nic_channel ));
     217
     218    // get pointers on NIC_TX[channel] chdev
     219    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[channel];
     220    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
     221    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
     222
     223    // build various TX extended pointers
     224    xptr_t    tx_lock_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_lock );
     225    xptr_t    tx_list_xp = XPTR( socket_cxy   , &socket_ptr->tx_list );
     226
     227    // get pointers on NIC_RX[channel] chdev
     228    xptr_t    rx_chdev_xp  = chdev_dir.nic_rx[channel];
     229    chdev_t * rx_chdev_ptr = GET_PTR( rx_chdev_xp );
     230    cxy_t     rx_chdev_cxy = GET_CXY( rx_chdev_xp );
     231
     232    // build various RX extended pointers
     233    xptr_t    rx_lock_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_lock );
     234    xptr_t    rx_list_xp = XPTR( socket_cxy   , &socket_ptr->rx_list );
     235
     236    // remove socket from the NIC_TX[channel] chdev clients queue
     237    remote_busylock_acquire( tx_lock_xp );
     238    xlist_unlink( tx_list_xp );
     239    remote_busylock_release( tx_lock_xp );
     240
     241    // remove socket from the NIC_RX[channel] chdev clients queue
     242    remote_busylock_acquire( rx_lock_xp );
     243    xlist_unlink( rx_list_xp );
     244    remote_busylock_release( rx_lock_xp );
     245
     246#if DEBUG_SOCKET_LINK
     247cycle = (uint32_t)hal_get_cycles();
     248if( DEBUG_SOCKET_LINK < cycle )
     249printk("\n[%s] thread[%x,%x] unlinked socket [%x,%d] / cycle %d\n",
     250__FUNCTION__, process->pid, this->trdid, socket_pid, socket_fdid, cycle );
     251#endif
     252
     253}  // end socket_unlink_from_servers()
     254       
     255/////////////////////////////////////////////////////////////////////////////////////////
     256// This static function is called by the socket_build() and socket_accept() functions.
     257// It allocates memory in cluster defined by the <cxy> argument for all structures
     258// associated to a socket: file descriptor, socket descriptor, RX buffer, R2T queue,
     259// and CRQ queue. It allocates an fdid, and register it in the process fd_array.
     260// It initialise the  the socket desccriptor static fields, other than local_addr,
     261// local_port, remote_addr, remote_port), and set the socket state to UNBOUND.
     262// It returns the local pointer on socket descriptor and the fdid value in buffers
     263// defined by the <socket_ptr> & <fdid_ptr> arguments.
     264/////////////////////////////////////////////////////////////////////////////////////////
     265// @ cxy        : [in]  target cluster fo socket & file descriptors.
     266// @ domain     : [in]  socket domain.
     267// @ type       : [in]  socket type.
     268// @ socket_ptr : [out] local pointer on buffer for socket pointer.
     269// @ fdid_ptr   : [out] local pointer on buffer for fdid value.
     270// # return 0 if success / return -1 if no memory.
     271/////////////////////////////////////////////////////////////////////////////////////////
     272static error_t socket_create( cxy_t       cxy,
     273                              uint32_t    domain,
     274                              uint32_t    type,
     275                              socket_t ** socket_ptr,
     276                              uint32_t  * fdid_ptr )
     277{
     278    uint32_t    fdid;
     279
     280    thread_t  * this    = CURRENT_THREAD;
     281    process_t * process = this->process;
     282
     283    kmem_req_t     req;
     284    socket_t     * socket;
     285    vfs_file_t   * file;
     286    uint32_t       state;
     287    error_t        error;
     288
     289#if DEBUG_SOCKET_CREATE
     290uint32_t cycle = (uint32_t)hal_get_cycles();
     291if( DEBUG_SOCKET_CREATE < cycle )
     292printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
     293__FUNCTION__, process->pid, this->trdid, cycle );
     294#endif
     295   
     296    // allocate memory for socket descriptor
     297    req.type   = KMEM_KCM;
     298    req.order  = bits_log2( sizeof(socket_t) );
     299    req.flags  = AF_ZERO;
     300    socket     = kmem_remote_alloc( cxy , &req );
     301
     302    if( socket == NULL )
     303    {
     304        printk("\n[ERROR] in %s : cannot allocate socket descriptor / thread[%x,%x]\n",
     305        __FUNCTION__, process->pid, this->trdid );
     306        return -1;
     307    }
     308
     309    // allocate memory for rx_buf buffer
     310    error = remote_buf_init( XPTR( cxy , &socket->rx_buf ),
     311                             NIC_RX_BUF_SIZE );
     312
     313    if( error )
     314    {
     315        printk("\n[ERROR] in %s : cannot allocate rx_buf / thread[%x,%x]\n",
     316        __FUNCTION__, process->pid, this->trdid );
     317        req.type = KMEM_KCM;
     318        req.ptr  = socket;
     319        kmem_remote_free( cxy , &req );
     320        return -1;
     321    }
     322
     323    // allocate memory for r2tq queue
     324    error = remote_buf_init( XPTR( cxy , &socket->r2tq ),
     325                             NIC_R2T_QUEUE_SIZE );
     326    if( error )
     327    {
     328        printk("\n[ERROR] in %s : cannot allocate R2T queue / thread[%x,%x]\n",
     329        __FUNCTION__, process->pid, this->trdid );
     330        remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
     331        req.type = KMEM_KCM;
     332        req.ptr  = socket;
     333        kmem_remote_free( cxy , &req );
     334        return -1;
     335    }
     336
     337    // don't allocate memory for crqq queue, as it is done by the socket_listen function
     338
     339    //  allocate memory for file descriptor
     340        req.type  = KMEM_KCM;
     341        req.order = bits_log2( sizeof(vfs_file_t) );
     342    req.flags = AF_ZERO;
     343        file      = kmem_remote_alloc( cxy , &req );
     344
     345    if( file == NULL )
     346    {
     347        printk("\n[ERROR] in %s : cannot allocate file descriptor / thread[%x,%x]\n",
     348        __FUNCTION__, process->pid, this->trdid );
     349        remote_buf_destroy( XPTR( cxy , &socket->r2tq ) );
     350        remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
     351        req.type = KMEM_KCM;
     352        req.ptr  = socket;
     353        kmem_remote_free( cxy , &req );
     354        return -1;
     355    }
     356   
     357    // get an fdid value, and register file descriptor in fd_array[]
     358    error = process_fd_register( process->ref_xp,
     359                                 XPTR( cxy , file ),
     360                                 &fdid );
     361    if ( error )
     362    {
     363        printk("\n[ERROR] in %s : cannot register file descriptor / thread[%x,%x]\n",
     364        __FUNCTION__, process->pid, this->trdid );
     365        req.type = KMEM_KCM;
     366        req.ptr  = file;
     367        kmem_free( &req );
     368        remote_buf_destroy( XPTR( cxy , &socket->r2tq ) );
     369        remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
     370        req.ptr  = socket;
     371        kmem_free( &req );
     372        return -1;
     373    }
     374
     375    state = (type == SOCK_STREAM) ? TCP_STATE_UNBOUND : UDP_STATE_UNBOUND;
     376
     377    // initialise socket descriptor
     378    hal_remote_s32( XPTR( cxy , &socket->pid         ) , process->pid );
     379    hal_remote_s32( XPTR( cxy , &socket->fdid        ) , fdid );
     380    hal_remote_s32( XPTR( cxy , &socket->domain      ) , domain );
     381    hal_remote_s32( XPTR( cxy , &socket->type        ) , type );
     382    hal_remote_s32( XPTR( cxy , &socket->state       ) , state );
     383    hal_remote_s64( XPTR( cxy , &socket->tx_client   ) , XPTR_NULL );
     384    hal_remote_s64( XPTR( cxy , &socket->rx_client   ) , XPTR_NULL );
     385    hal_remote_s32( XPTR( cxy , &socket->tx_valid    ) , false );
     386    hal_remote_s32( XPTR( cxy , &socket->rx_valid    ) , false );
     387    hal_remote_s32( XPTR( cxy , &socket->nic_channel ) , 0 );
     388
     389    // initialize file descriptor
     390    hal_remote_s32( XPTR( cxy , &file->type        ) , INODE_TYPE_SOCK );
     391    hal_remote_spt( XPTR( cxy , &file->socket      ) , socket );
     392    hal_remote_s32( XPTR( cxy , &file->refcount    ) , 1 );
     393
     394    // initialize socket lock
     395    remote_queuelock_init( XPTR( cxy , &socket->lock ) , LOCK_SOCKET_STATE );
     396
     397#if DEBUG_SOCKET_CREATE
     398if( DEBUG_SOCKET_CREATE < cycle )
     399printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / xptr[%x,%x] / cycle %d\n",
     400__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cxy, socket, cycle );
     401#endif
     402   
     403    // return success
     404    *socket_ptr = socket;
     405    *fdid_ptr   = fdid;
     406
     407    return 0;
     408
     409}  // end socket_create
     410
     411/////////////////////////////////////////////////////////////////////////////////////////
     412// This static function is called by the socket_close() function to destroy a socket
     413// identified by the <file_xp> argument.
     414// It remove the associated file from the reference process fd_array. It unlink the
     415// socket from the NIC_TX [k] and NIC_RX[k] chdevs. It release all memory allocated
     416// for the structures associated to the target socket socket : file descriptor,
     417// socket descriptor, RX buffer, R2T queue, CRQ queue.
     418/////////////////////////////////////////////////////////////////////////////////////////
     419// @ file_xp  : extended pointer on the file descriptor.
     420/////////////////////////////////////////////////////////////////////////////////////////
     421static void socket_destroy( xptr_t file_xp )
     422{
     423    kmem_req_t          req;
     424
     425    thread_t  * this    = CURRENT_THREAD;
     426    process_t * process = this->process;
     427
     428// check file_xp argument
     429assert( (file_xp != XPTR_NULL), "illegal argument\n" );
     430
     431    // get cluster & local pointer for file descriptor
     432    vfs_file_t * file_ptr = GET_PTR( file_xp );
     433    cxy_t        file_cxy = GET_CXY( file_xp );
     434
     435#if DEBUG_SOCKET_DESTROY
     436uint32_t cycle = (uint32_t)hal_get_cycles();
     437if( DEBUG_SOCKET_DESTROY < cycle )
     438printk("\n[%s] thread[%x,%x] enter / file[%x,%x] / cycle %d\n",
     439__FUNCTION__, process->pid, this->trdid, file_cxy, file_ptr, cycle );
     440#endif
     441
     442    // get local pointer for socket and file type
     443    socket_t * socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     444    uint32_t   file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     445   
     446// check file descriptor type
     447assert( (file_type == INODE_TYPE_SOCK), "illegal file type\n" );
     448
     449    // get socket nic_channel and fdid
     450    uint32_t channel = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
     451    uint32_t fdid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->fdid ));
     452
     453    // remove socket from NIC_TX & NIC_RX chdev queues when socket is connected
     454    if( channel < LOCAL_CLUSTER->nb_nic_channels )
     455    {
     456        socket_unlink_from_servers( XPTR( file_cxy , socket_ptr ) );
     457    }
     458
     459    // remove the file descriptor from the fd_array
     460    process_fd_remove( process->owner_xp , fdid );
     461
     462    // release memory allocated for file descriptor
     463    req.type = KMEM_KCM;
     464    req.ptr  = file_ptr;
     465    kmem_remote_free( file_cxy , &req );
     466
     467    // release memory allocated for buffers attached to socket descriptor
     468    remote_buf_destroy( XPTR( file_cxy , &socket_ptr->crqq ) );
     469    remote_buf_destroy( XPTR( file_cxy , &socket_ptr->r2tq ) );
     470    remote_buf_destroy( XPTR( file_cxy , &socket_ptr->rx_buf ) );
     471
     472    // release memory allocated for socket descriptor
     473    req.type = KMEM_KCM;
     474    req.ptr  = socket_ptr;
     475    kmem_remote_free( file_cxy , &req );
     476
     477#if DEBUG_SOCKET_DESTROY
     478cycle = (uint32_t)hal_get_cycles();
     479if( DEBUG_SOCKET_DESTROY < cycle )
     480printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
     481__FUNCTION__, process->pid, this->trdid, cycle );
     482#endif
     483
     484}  // end socket_destroy()
     485
     486////////////////////////////////////////////////
     487void socket_put_r2t_request( xptr_t    queue_xp,
     488                             uint32_t  flags,
     489                             uint32_t  channel )
     490{
     491    xptr_t     chdev_xp;
     492    cxy_t      chdev_cxy;
     493    chdev_t  * chdev_ptr;
     494    thread_t * server_ptr;
     495    xptr_t     server_xp;
     496
     497    while( 1 )
     498    {
     499        // try to register R2T request
     500        error_t error = remote_buf_put_from_kernel( queue_xp,
     501                                                    (uint8_t *)(&flags),
     502                                                    1 );
     503        if( error )
     504        {
     505            // queue full => wait and retry
     506            sched_yield( "waiting R2T queue" );
     507        }
     508        else
     509        {
     510            // get NIC_TX chdev pointers
     511            chdev_xp = chdev_dir.nic_tx[channel];
     512            chdev_cxy = GET_CXY( chdev_xp );
     513            chdev_ptr = GET_PTR( chdev_xp );
    216514 
    217 #endif  /* _SOCKET_H_ */
     515            // get NIC_TX server thread pointers
     516            server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server ) );
     517            server_xp  = XPTR( chdev_cxy , server_ptr );
     518
     519            // unblocks NIC_TX server thread
     520            thread_unblock( server_xp , THREAD_BLOCKED_CLIENT );
     521
     522            return;
     523        }
     524    }
     525}  // end socket_put_r2t_request()
     526 
     527///////////////////////////////////////////////////
     528error_t socket_put_crq_request( xptr_t    queue_xp,
     529                                uint32_t  remote_addr,
     530                                uint32_t  remote_port,
     531                                uint32_t  remote_iss,
     532                                uint32_t  remote_window )
     533{
     534    connect_request_t   req;
     535
     536    // build request
     537    req.addr   = remote_addr;
     538    req.port   = remote_port;
     539    req.iss    = remote_iss;
     540    req.window = remote_window;
     541
     542    // try to register request in CRQ
     543    return remote_buf_put_from_kernel( queue_xp,
     544                                       (uint8_t *)(&req),
     545                                       sizeof(connect_request_t) );
     546}  // end socket_put_crq_request()
     547 
     548////////////////////////////////////////////////////
     549error_t socket_get_crq_request( xptr_t     queue_xp,
     550                                uint32_t * remote_addr,
     551                                uint32_t * remote_port,
     552                                uint32_t * remote_iss,
     553                                uint32_t * remote_window )
     554{
     555    connect_request_t   req;
     556    error_t             error;
     557
     558    // get request from CRQ
     559    error = remote_buf_get_to_kernel( queue_xp,
     560                                      (uint8_t *)(&req),
     561                                      sizeof(connect_request_t) );
     562    // extract request arguments
     563    *remote_addr   = req.addr;
     564    *remote_port   = req.port;
     565    *remote_iss    = req.iss;
     566    *remote_window = req.window;
     567
     568    return error;
     569
     570}  // end socket_get_crq_request()
     571 
     572
     573/////////////////////////////////////////////////////////////////////////////////////////
     574//                 Functions implementing the SOCKET related syscalls
     575/////////////////////////////////////////////////////////////////////////////////////////
     576
     577//////////////////////////////////////
     578int socket_build( uint32_t   domain,
     579                  uint32_t   type )
     580{
     581    uint32_t    fdid;
     582    socket_t  * socket;
     583    error_t     error;
     584
     585#if DEBUG_SOCKET_BUILD
     586uint32_t    cycle   = (uint32_t)hal_get_cycles();
     587thread_t  * this    = CURRENT_THREAD;
     588process_t * process = this->process;
     589if( DEBUG_SOCKET_BUILD < cycle )
     590printk("\n[%s] thread[%x,%x] enter / %s / %s / cycle %d\n",
     591__FUNCTION__, process->pid, this->trdid,
     592socket_domain_str(domain), socket_type_str(type), cycle );
     593#endif
     594
     595
     596    // allocate memory for the file descriptor and for the socket
     597    error = socket_create( local_cxy,
     598                           domain,
     599                           type,
     600                           &socket,
     601                           &fdid );
     602
     603#if DEBUG_SOCKET_BUILD
     604cycle = (uint32_t)hal_get_cycles();
     605if( DEBUG_SOCKET_BUILD < cycle )
     606printk("\n[%s] thread[%x,%x] exit / socket %x / fdid %d / %s / cycle %d\n",
     607__FUNCTION__, process->pid, this->trdid, socket, fdid,
     608socket_state_str(hal_remote_l32(XPTR(local_cxy , &socket->state))),
     609cycle );
     610#endif
     611
     612    if( error ) return -1;
     613    return fdid;
     614}
     615
     616////////////////////////////////
     617int socket_bind( uint32_t  fdid,
     618                 uint32_t  addr,
     619                 uint16_t  port )
     620{
     621    vfs_inode_type_t    file_type;
     622    socket_t          * socket;
     623    uint32_t            socket_type;
     624    uint32_t            socket_state;
     625
     626    thread_t  * this    = CURRENT_THREAD;
     627    process_t * process = this->process;
     628
     629#if DEBUG_SOCKET_BIND
     630uint32_t cycle = (uint32_t)hal_get_cycles();
     631if( DEBUG_SOCKET_BIND < cycle )
     632printk("\n[%s] thread[%x,%x] enter / socket[%x,%d] / addr %x / port %x / cycle %d\n",
     633__FUNCTION__, process->pid, this->trdid, process->pid, fdid, addr, port, cycle );
     634#endif
     635
     636    // get pointers on file descriptor
     637    xptr_t       file_xp  = process_fd_get_xptr_from_local( process , fdid );
     638    vfs_file_t * file_ptr = GET_PTR( file_xp );
     639    cxy_t        file_cxy = GET_CXY( file_xp );
     640
     641    // check file_xp
     642    if( file_xp == XPTR_NULL )
     643    {
     644        printk("\n[ERROR] in %s : undefined fdid %d / thread[%x,%x]\n",
     645        __FUNCTION__, fdid, process->pid, this->trdid );
     646        return -1;
     647    }
     648
     649    file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     650    socket    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     651
     652    // check file descriptor type
     653    if( file_type != INODE_TYPE_SOCK )
     654    {
     655        printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x]",
     656        __FUNCTION__, vfs_inode_type_str( file_type ), process->pid, this->trdid );
     657        return -1;
     658    }
     659
     660    // get socket type
     661    socket_type = hal_remote_l32(XPTR( file_cxy , &socket->type ));
     662
     663    // compute socket state
     664    socket_state = (socket_type == SOCK_STREAM) ? TCP_STATE_BOUND : UDP_STATE_BOUND;
     665
     666    // update the socket descriptor
     667    hal_remote_s32( XPTR( file_cxy , &socket->local_addr ) , addr );
     668    hal_remote_s32( XPTR( file_cxy , &socket->local_port ) , port );
     669    hal_remote_s32( XPTR( file_cxy , &socket->state      ) , socket_state );
     670
     671#if DEBUG_SOCKET_BIND
     672cycle = (uint32_t)hal_get_cycles();
     673if( DEBUG_SOCKET_BIND < cycle )
     674printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / %s / addr %x / port %x / cycle %d\n",
     675__FUNCTION__, process->pid, this->trdid, process->pid, fdid,
     676socket_state_str(hal_remote_l32( XPTR( file_cxy , &socket->state ))),
     677hal_remote_l32( XPTR( file_cxy , &socket->local_addr )),
     678hal_remote_l32( XPTR( file_cxy , &socket->local_port )),
     679cycle );
     680#endif
     681
     682    return 0;
     683
     684}  // end socket_bind()
     685
     686//////////////////////////////////
     687int socket_listen( uint32_t fdid,
     688                   uint32_t crq_depth )
     689{
     690    xptr_t              file_xp;
     691    vfs_file_t        * file_ptr;
     692    cxy_t               file_cxy;
     693    vfs_inode_type_t    file_type;
     694    socket_t          * socket_ptr;
     695    uint32_t            socket_type;
     696    uint32_t            socket_state;
     697    uint32_t            socket_local_addr;
     698    uint32_t            socket_local_port;
     699    error_t             error;
     700
     701    thread_t  * this    = CURRENT_THREAD;
     702    process_t * process = this->process;
     703
     704#if DEBUG_SOCKET_LISTEN
     705uint32_t cycle = (uint32_t)hal_get_cycles();
     706if( DEBUG_SOCKET_LISTEN < cycle )
     707printk("\n[%s] thread[%x,%x] enter / socket[%x,%d] / crq_depth %x / cycle %d\n",
     708__FUNCTION__, process->pid, this->trdid, process->pid, fdid, crq_depth, cycle );
     709#endif
     710
     711    // get pointers on file descriptor
     712    file_xp  = process_fd_get_xptr_from_local( process , fdid );
     713    file_ptr = GET_PTR( file_xp );
     714    file_cxy = GET_CXY( file_xp );
     715
     716    // check file_xp
     717    if( file_xp == XPTR_NULL )
     718    {
     719        printk("\n[ERROR] in %s : undefined fdid %d / thread[%x,%x]\n",
     720        __FUNCTION__, fdid, process->pid, this->trdid );
     721        return -1;
     722    }
     723
     724    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     725    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     726
     727    // check file descriptor type
     728    if( file_type != INODE_TYPE_SOCK )
     729    {
     730        printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x]\n",
     731        __FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid );
     732        return -1;
     733    }
     734
     735    // get relevant infos from <fdid> socket descriptor
     736    socket_type       = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
     737    socket_state      = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     738    socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_addr ));
     739    socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_port ));
     740
     741    // check socket type
     742    if( socket_type != SOCK_STREAM )
     743    {
     744        printk("\n[ERROR] in %s : illegal socket type %s / thread[%x,%x]\n",
     745        __FUNCTION__, socket_type_str(socket_type), process->pid, this->trdid );
     746        return -1;
     747    }
     748   
     749    // check socket state
     750    if( socket_state != TCP_STATE_BOUND )
     751    {
     752        printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x]\n",
     753        __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
     754        return -1;
     755    }
     756   
     757    // compute CRQ queue depth : max( crq_depth , NIC_CRQ_QUEUE_SIZE )
     758    uint32_t depth = ( crq_depth > NIC_CRQ_QUEUE_SIZE ) ? crq_depth : NIC_CRQ_QUEUE_SIZE;
     759
     760    // allocate memory for the CRQ queue
     761    error = remote_buf_init( XPTR( file_cxy , &socket_ptr->crqq ),
     762                                   depth * sizeof(connect_request_t) );
     763    if( error )
     764    {
     765        printk("\n[ERROR] in %s : cannot allocate CRQ queue / thread[%x,%x]\n",
     766        __FUNCTION__, process->pid, this->trdid );
     767        return -1;
     768    }
     769
     770    // update socket.state
     771    hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , TCP_STATE_LISTEN );
     772
     773    // get pointers on NIC_RX[0] chdev
     774    xptr_t    rx0_chdev_xp  = chdev_dir.nic_rx[0];
     775    chdev_t * rx0_chdev_ptr = GET_PTR( rx0_chdev_xp );
     776    cxy_t     rx0_chdev_cxy = GET_CXY( rx0_chdev_xp );
     777   
     778    // build extended pointers on list of listening sockets
     779    xptr_t    rx0_root_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.root );
     780    xptr_t    rx0_lock_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.lock );
     781
     782    // build extended pointer on socket rx_list field
     783    xptr_t    list_entry_xp = XPTR( file_cxy , &socket_ptr->rx_list );
     784
     785    // register  <fdid> socket in listening sockets list
     786    remote_busylock_acquire( rx0_lock_xp );
     787    xlist_add_last( rx0_root_xp , list_entry_xp );
     788    remote_busylock_release( rx0_lock_xp );
     789
     790#if DEBUG_SOCKET_LISTEN
     791cycle = (uint32_t)hal_get_cycles();
     792if( DEBUG_SOCKET_LISTEN < cycle )
     793printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / %s / cycle %d\n",
     794__FUNCTION__, process->pid, this->trdid, process->pid, fdid,
     795socket_state_str(socket_state), cycle );
     796#endif
     797
     798    return 0;
     799
     800}  // end socket_listen()
     801
     802///////////////////////////////////
     803int socket_accept( uint32_t   fdid,
     804                   uint32_t * remote_addr,
     805                   uint16_t * remote_port )
     806{
     807    xptr_t              file_xp;             // extended pointer on remote file
     808    vfs_file_t        * file_ptr;
     809    cxy_t               file_cxy;
     810    vfs_inode_type_t    file_type;           // file descriptor type
     811    socket_t          * socket_ptr;          // local pointer on remote waiting socket
     812    uint32_t            socket_type;         // listening socket type   
     813    uint32_t            socket_state;        // listening socket state
     814    uint32_t            socket_domain;       // listening socket domain
     815    uint32_t            socket_local_addr;   // listening socket local IP address
     816    uint32_t            socket_local_port;   // listening socket local port
     817    uint32_t            socket_tx_nxt;       // listening socket tx_nxt
     818    bool_t              socket_tx_valid;     // listening socket tx_valid
     819    xptr_t              socket_tx_client;    // listening socket tx_client thread
     820    bool_t              socket_rx_valid;     // listening socket rx_valid
     821    xptr_t              socket_rx_client;    // listening socket rx_client thread
     822    xptr_t              socket_lock_xp;      // listening socket lock
     823    xptr_t              crq_xp;              // listening socket CRQ queue
     824    uint32_t            crq_status;          // number of bytes in CRQ
     825    cxy_t               new_socket_cxy;      // new socket cluster identifier
     826    socket_t          * new_socket_ptr;      // local pointer on new socket
     827    xptr_t              new_socket_xp;       // extended pointer on new socket
     828    volatile uint32_t   new_state;           // new socket state (modified by NIC_RX thread)
     829    uint32_t            new_fdid;            // new socket file descriptor index
     830    uint32_t            new_remote_addr;     // new socket remote IP address
     831    uint32_t            new_remote_port;     // new socket remote port
     832    uint32_t            new_remote_iss;      // new socket remote iss
     833    uint32_t            new_remote_window;   // new socket receive window
     834    xptr_t              tx_server_xp;        // extended pointer on TX server thread
     835    thread_t          * tx_server_ptr;       // local pointer on TX server thread
     836    uint32_t            cmd_status;          // command status (rx_sts or tx_sts)
     837    bool_t              cmd_valid;           // valid command (rx_valid or tx_valid)
     838    error_t             error;
     839
     840    thread_t  * this      = CURRENT_THREAD;
     841    xptr_t      client_xp = XPTR( local_cxy , this );
     842    process_t * process   = this->process;
     843
     844#if DEBUG_SOCKET_ACCEPT
     845uint32_t cycle = (uint32_t)hal_get_cycles();
     846if( DEBUG_SOCKET_ACCEPT < cycle )
     847printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / cycle %d\n",
     848__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     849#endif
     850
     851    // 1) get pointers on file descriptor
     852    file_xp  = process_fd_get_xptr_from_local( process , fdid );
     853    file_ptr = GET_PTR( file_xp );
     854    file_cxy = GET_CXY( file_xp );
     855
     856    // check file_xp
     857    if( file_xp == XPTR_NULL )
     858    {
     859        printk("\n[ERROR] in %s : undefined fdid %d",
     860        __FUNCTION__, fdid );
     861        return -1;
     862    }
     863 
     864    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     865    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     866
     867    // check file descriptor type
     868    if( file_type != INODE_TYPE_SOCK )
     869    {
     870        printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x]\n",
     871        __FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid );
     872        return -1;
     873    }
     874
     875    // build extended pointer on listening socket lock
     876    socket_lock_xp = XPTR( file_cxy , &socket_ptr->lock );
     877
     878    // acquire listening socket lock
     879    remote_queuelock_acquire( socket_lock_xp );
     880                   
     881    // get listening socket type, domain, state, local_addr, local_port & tx_nxt
     882    socket_type       = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
     883    socket_state      = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     884    socket_domain     = hal_remote_l32( XPTR( file_cxy , &socket_ptr->domain ));
     885    socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_addr ));
     886    socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_port ));
     887    socket_tx_nxt     = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_nxt ));
     888    socket_tx_valid   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ));
     889    socket_tx_client  = hal_remote_l64( XPTR( file_cxy , &socket_ptr->tx_client ));
     890    socket_rx_valid   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid ));
     891    socket_rx_client  = hal_remote_l64( XPTR( file_cxy , &socket_ptr->rx_client ));
     892
     893    // check socket type
     894    if( socket_type != SOCK_STREAM )
     895    {
     896        // release listening socket lock
     897        remote_queuelock_release( socket_lock_xp );
     898                   
     899        printk("\n[ERROR] in %s : illegal socket type %s / thread[%x,%x]\n",
     900        __FUNCTION__, socket_type_str(socket_type), process->pid , this->trdid );
     901        return -1;
     902    }
     903   
     904    // check socket state
     905    if( socket_state != TCP_STATE_LISTEN )
     906    {
     907        // release listening socket lock
     908        remote_queuelock_release( socket_lock_xp );
     909                   
     910        printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x]\n",
     911        __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
     912        return -1;
     913    }
     914   
     915    // check no previous RX command
     916    if( (socket_rx_valid == true) || (socket_rx_client != XPTR_NULL) )
     917    {
     918        // release listening socket lock
     919        remote_queuelock_release( socket_lock_xp );
     920                   
     921        printk("\n[ERROR] in %s : previous RX cmd on socket[%x,%d] / thread[%x,%x]\n",
     922        __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     923        return -1;
     924    }
     925
     926    // check no previous TX command
     927    if( (socket_tx_valid == true) || (socket_tx_client != XPTR_NULL) )
     928    {
     929        // release socket lock
     930        remote_queuelock_release( socket_lock_xp );
     931                   
     932        printk("\n[ERROR] in %s : previous TX cmd on socket[%x,%d] / thread[%x,%x]\n",
     933        __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     934        return -1;
     935    }
     936
     937    // 2) build extended pointer on listening socket.crq
     938    crq_xp  = XPTR( file_cxy , &socket_ptr->crqq );
     939
     940    // get CRQ status
     941    crq_status = remote_buf_status( crq_xp );
     942
     943    // block & deschedule when CRQ empty
     944    if( crq_status == 0 )
     945    {
     946        // register command arguments in listening socket
     947        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_cmd    ), CMD_RX_ACCEPT );
     948        hal_remote_s64( XPTR( file_cxy , &socket_ptr->rx_client ), client_xp );
     949        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_valid  ), true );
     950
     951        // release listening socket lock
     952        remote_queuelock_release( socket_lock_xp );
     953
     954#if DEBUG_SOCKET_ACCEPT
     955cycle = (uint32_t)hal_get_cycles();
     956if( DEBUG_SOCKET_ACCEPT < cycle )
     957printk("\n[%s] thread[%x,%x] socket[%x,%d] / CRQ empty => blocks on <IO> / cycle %d\n",
     958__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     959#endif
     960        // block & deschedule when CRQQ empty
     961        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     962        sched_yield( "CRQ queue empty");
     963
     964#if DEBUG_SOCKET_ACCEPT
     965cycle = (uint32_t)hal_get_cycles();
     966if( DEBUG_SOCKET_ACCEPT < cycle )
     967printk("\n[%s] thread[%x,%x] socket[%x,%d] / resumes / cycle %d\n",
     968__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     969#endif
     970        // take listening socket lock
     971        remote_queuelock_acquire( socket_lock_xp );
     972
     973        // get CRQ status & command status
     974        cmd_valid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid ) );
     975        cmd_status   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_sts ) );
     976        crq_status   = remote_buf_status( crq_xp );
     977
     978assert( (((crq_status > 0) || (cmd_status!= CMD_STS_SUCCESS)) && (cmd_valid == false)),
     979"illegal socket state when client thread resumes after RX_ACCEPT" );
     980
     981        // reset socket.rx_client
     982        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_client ) , XPTR_NULL );
     983
     984        if( cmd_status != CMD_STS_SUCCESS )
     985        {
     986            // release socket lock
     987            remote_queuelock_release( socket_lock_xp );
     988
     989            printk("\n[ERROR] in %s for RX_ACCEPT command / socket[%x,%d] / thread[%x,%x]\n",
     990            __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     991            return -1;
     992        }
     993
     994        // extract first request from the listening socket CRQ
     995        error = socket_get_crq_request( crq_xp,
     996                                    &new_remote_addr,
     997                                    &new_remote_port,
     998                                    &new_remote_iss,
     999                                    &new_remote_window );
     1000
     1001assert( (error == 0),
     1002"cannot get a connection request from a non-empty CRQ" );
     1003
     1004        // reset listening socket rx_client
     1005        hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_client ) , XPTR_NULL );
     1006
     1007        // release socket lock
     1008        remote_queuelock_release( socket_lock_xp );
     1009
     1010    }  // end blocking on CRQ status
     1011
     1012    // from this point, we can create a new socket
     1013    // and ask the NIC_TX to send a SYN-ACK segment
     1014
     1015#if DEBUG_SOCKET_ACCEPT
     1016cycle = (uint32_t)hal_get_cycles();
     1017if( DEBUG_SOCKET_ACCEPT < cycle )
     1018printk("\n[%s] thread[%x,%x] socket[%x,%d] / got a CRQ request / cycle %d\n",
     1019__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     1020#endif
     1021
     1022    // 3) select a cluster for the new socket
     1023    new_socket_cxy = cluster_random_select();
     1024
     1025    // allocate memory for the new socket descriptor
     1026    error = socket_create( new_socket_cxy,
     1027                           socket_domain,
     1028                           socket_type,
     1029                           &new_socket_ptr,
     1030                           &new_fdid );
     1031    if( error )
     1032    {
     1033        printk("\n[ERROR] in %s : cannot allocate new socket / thread[%x,%x]\n",
     1034        __FUNCTION__, process->pid, this->trdid );
     1035        return -1;
     1036    }
     1037   
     1038    // build extended poiner on new socket
     1039    new_socket_xp = XPTR( new_socket_cxy , new_socket_ptr );
     1040
     1041#if DEBUG_SOCKET_ACCEPT
     1042cycle = (uint32_t)hal_get_cycles();
     1043if( DEBUG_SOCKET_ACCEPT < cycle )
     1044printk("\n[%s] thread[%x,%x] created new socket[%x,%d] / cycle %d\n",
     1045__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid, cycle );
     1046#endif
     1047       
     1048    // compute NIC channel index from remote_addr and remote_port
     1049    uint32_t new_nic_channel = dev_nic_get_key( new_remote_addr , new_remote_port );
     1050
     1051    // update new socket descriptor
     1052    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->local_addr ) , socket_local_addr );
     1053    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->local_port ) , socket_local_port );
     1054    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->remote_addr) , new_remote_addr );
     1055    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->remote_port) , new_remote_port );
     1056    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->nic_channel) , new_nic_channel );
     1057    hal_remote_s32(XPTR(new_socket_cxy , &new_socket_ptr->state      ) , TCP_STATE_SYN_RCVD );
     1058
     1059    // set new socket TCB : increment tx_nxt / initialize rx_nxt, rx_irs, rx_wnd
     1060    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->tx_nxt ), socket_tx_nxt + 1 );
     1061    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->rx_nxt ), new_remote_iss + 1 );
     1062    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->rx_irs ), new_remote_iss );
     1063    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->rx_wnd ), new_remote_window );
     1064
     1065    // link new socket to chdev servers
     1066    socket_link_to_servers( new_socket_xp , new_nic_channel );
     1067
     1068    // 3) get pointers on NIC_TX[channel] chdev
     1069    xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[new_nic_channel];
     1070    chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
     1071    cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
     1072
     1073    // get pointers on NIC_TX[channel] server thread
     1074    tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
     1075    tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
     1076
     1077    // register command arguments in new socket to request a SYN_ACK segment
     1078    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->tx_cmd    ), CMD_TX_ACCEPT );
     1079    hal_remote_s64( XPTR( new_socket_cxy , &new_socket_ptr->tx_client ), client_xp );
     1080    hal_remote_s32( XPTR( new_socket_cxy , &new_socket_ptr->tx_valid  ), true );
     1081
     1082    // unblock NIC_TX server thread
     1083    thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
     1084 
     1085#if DEBUG_SOCKET_ACCEPT
     1086cycle = (uint32_t)hal_get_cycles();
     1087if( DEBUG_SOCKET_ACCEPT < cycle )
     1088printk("\n[%s] thread[%x,%x] new_socket[%x,%d] blocks on <IO> waiting ESTAB / cycle %d\n",
     1089__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid, cycle );
     1090#endif
     1091
     1092    // client thread blocks & deschedules
     1093    thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     1094    sched_yield( "waiting new socket connection");
     1095
     1096#if DEBUG_SOCKET_ACCEPT
     1097cycle = (uint32_t)hal_get_cycles();
     1098if( DEBUG_SOCKET_ACCEPT < cycle )
     1099printk("\n[%s] thread[%x,%x] new_socket[%x,%d] resumes  / cycle %d\n",
     1100__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid, cycle );
     1101#endif
     1102
     1103    // get new socket state, tx_valid and tx_sts
     1104    new_state  = hal_remote_l32( XPTR( new_socket_cxy , &new_socket_ptr->state ));
     1105    cmd_valid  = hal_remote_l32( XPTR( new_socket_cxy , &new_socket_ptr->tx_valid ));
     1106    cmd_status = hal_remote_l32( XPTR( new_socket_cxy , &new_socket_ptr->tx_sts ));
     1107
     1108assert( (((new_state == TCP_STATE_ESTAB) || (cmd_status != CMD_STS_SUCCESS))
     1109        && (cmd_valid == false)),
     1110"illegal socket state when client thread resumes after TX_ACCEPT" );
     1111
     1112    // reset socket.tx_client
     1113    hal_remote_s64( XPTR( new_socket_cxy , &new_socket_ptr->tx_client ) , XPTR_NULL );
     1114
     1115    if( cmd_status != CMD_STS_SUCCESS )
     1116    {
     1117        printk("\n[ERROR] in %s for TX_ACCEPT command / socket[%x,%d] / thread[%x,%x]\n",
     1118        __FUNCTION__, process->pid, new_fdid, process->pid, this->trdid );
     1119        return -1;
     1120    }
     1121    else
     1122    {
     1123
     1124#if DEBUG_SOCKET_ACCEPT
     1125cycle = (uint32_t)hal_get_cycles();
     1126if( DEBUG_SOCKET_ACCEPT < cycle )
     1127printk("\n[%s] thread[%x,%x] new_socket[%x,%d] / state %s / addr %x / port %x / cycle %d\n",
     1128__FUNCTION__, process->pid, this->trdid, process->pid, new_fdid,
     1129socket_state_str(new_state), new_remote_addr, new_remote_port, cycle );
     1130#endif
     1131
     1132        // return success
     1133        *remote_addr = new_remote_addr;
     1134        *remote_port = new_remote_port;
     1135        return new_fdid;
     1136    }
     1137 
     1138}  // end socket_accept()
     1139
     1140//////////////////////////////////
     1141int socket_connect( uint32_t fdid,
     1142                    uint32_t remote_addr,
     1143                    uint16_t remote_port )
     1144{
     1145    vfs_inode_type_t    file_type;
     1146    socket_t          * socket_ptr;       // local pointer on thread descriptor
     1147    volatile uint32_t   socket_state;     // socket state (modified by the NIC_TX thread)
     1148    uint32_t            socket_type;      // socket type 
     1149    uint32_t            local_addr;       // local IP address
     1150    uint32_t            local_port;       // local port
     1151    xptr_t              tx_server_xp;     // extended pointer on TX server thread
     1152    thread_t          * tx_server_ptr;    // local pointer on TX server thread
     1153    uint32_t            nic_channel;      // NIC channel index
     1154    uint32_t            cmd_status;       // command status (tx_sts field)
     1155    bool_t              cmd_valid;        // command valid (tx_valid field)
     1156
     1157    thread_t  * this      = CURRENT_THREAD;
     1158    xptr_t      client_xp = XPTR( local_cxy , this );
     1159
     1160    // get pointers on file descriptor
     1161    xptr_t       file_xp  = process_fd_get_xptr_from_local( this->process , fdid );
     1162    vfs_file_t * file_ptr = GET_PTR( file_xp );
     1163    cxy_t        file_cxy = GET_CXY( file_xp );
     1164
     1165    // check file_xp
     1166    if( file_xp == XPTR_NULL )
     1167    {
     1168        printk("\n[ERROR] in %s : undefined fdid %d",
     1169        __FUNCTION__, fdid );
     1170        return -1;
     1171    }
     1172
     1173    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     1174    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     1175
     1176#if DEBUG_SOCKET_CONNECT
     1177uint32_t cycle = (uint32_t)hal_get_cycles();
     1178pid_t    pid   = this->process->pid;
     1179trdid_t  trdid = this->trdid;
     1180if( DEBUG_SOCKET_CONNECT < cycle )
     1181printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] / addr %x / port %d / cycle %d\n",
     1182__FUNCTION__,  pid, trdid, pid, fdid, remote_addr, remote_port, cycle );
     1183#endif
     1184
     1185    // check file descriptor type
     1186    if( file_type != INODE_TYPE_SOCK )
     1187    {
     1188        printk("\n[ERROR] in %s : illegal file type %s",
     1189        __FUNCTION__, vfs_inode_type_str( file_type ) );
     1190        return -1;
     1191    }
     1192
     1193    // get relevant socket infos
     1194    socket_type   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ) );
     1195    socket_state  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ) );
     1196    local_addr    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_addr ) );
     1197    local_port    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->local_port ) );
     1198
     1199    if( socket_type == SOCK_DGRAM )       // UDP
     1200    {
     1201        if( socket_state != UDP_STATE_BOUND )
     1202        {
     1203            printk("\n[ERROR] in %s : illegal socket state %s for type %s",
     1204            __FUNCTION__, socket_state_str(socket_state), socket_type_str(socket_type) );
     1205            return -1;
     1206        }
     1207    }
     1208    else if( socket_type == SOCK_STREAM )  // TCP
     1209    {
     1210        if( socket_state != TCP_STATE_BOUND )
     1211        {
     1212            printk("\n[ERROR] in %s : illegal socket state %s for type %s",
     1213            __FUNCTION__, socket_state_str(socket_state), socket_type_str(socket_type) );
     1214            return -1;
     1215        }
     1216    }
     1217    else
     1218    {
     1219        printk("\n[ERROR] in %s : illegal socket type %s",
     1220        __FUNCTION__,  socket_type_str(socket_type) );
     1221        return -1;
     1222    }
     1223
     1224    // compute nic_channel index from remote_addr and remote_port
     1225    nic_channel = dev_nic_get_key( remote_addr , remote_port );
     1226
     1227    // link socket to chdev servers
     1228    socket_link_to_servers( XPTR( file_cxy , socket_ptr ), nic_channel );
     1229
     1230    // update the socket descriptor
     1231    hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_addr ) , remote_addr  );
     1232    hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_port ) , remote_port  );
     1233    hal_remote_s32( XPTR( file_cxy , &socket_ptr->nic_channel ) , nic_channel  );
     1234
     1235    // the actual connection mechanism depends on socket type
     1236    // UDP : client thread updates the local socket state without blocking
     1237    // TCP : client thread request TX server thread to start the 3 steps handshake
     1238
     1239    if( socket_type == SOCK_DGRAM )  // UDP
     1240    {
     1241        // directly update the local socket state
     1242        hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , UDP_STATE_ESTAB );
     1243
     1244        return 0;
     1245    }
     1246    else                             // TCP
     1247    {
     1248        // get pointers on NIC_TX[channel] chdev
     1249        xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
     1250        chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
     1251        cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
     1252
     1253        // get pointers on NIC_TX[channel] server thread
     1254        tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
     1255        tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
     1256
     1257        // register command arguments in socket descriptor for a SYN segment
     1258        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd    ), CMD_TX_CONNECT );
     1259        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ), client_xp );
     1260        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_valid  ), true );
     1261
     1262        // unblock NIC_TX server thread
     1263        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
     1264 
     1265#if DEBUG_SOCKET_CONNECT
     1266cycle = (uint32_t)hal_get_cycles();
     1267if( DEBUG_SOCKET_CONNECT < cycle )
     1268printk("\n[%s] thread[%x,%x] socket[%x,%d] blocks on <IO> waiting connexion / cycle %d \n",
     1269__FUNCTION__, pid, trdid, pid, fdid, cycle );
     1270#endif
     1271        // block itself and deschedule
     1272        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     1273        sched_yield( "waiting connection" );
     1274
     1275#if DEBUG_SOCKET_CONNECT
     1276cycle = (uint32_t)hal_get_cycles();
     1277if( DEBUG_SOCKET_CONNECT < cycle )
     1278printk("\n[%s] thread[%x,%x] socket[%x,%d] / resumes / cycle %d \n",
     1279__FUNCTION__, pid, trdid, pid, fdid, cycle );
     1280#endif
     1281
     1282        // get socket state, tx_valid and tx_sts
     1283        cmd_valid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ));
     1284        cmd_status   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_sts ));
     1285        socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     1286
     1287assert( (((socket_state == TCP_STATE_ESTAB) || (cmd_status != CMD_STS_SUCCESS))
     1288        && (cmd_valid == false)),
     1289"illegal socket state when client thread resumes after TX_CONNECT" );
     1290
     1291        // reset socket.tx_client
     1292        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_client ) , XPTR_NULL );
     1293
     1294        if( cmd_status != CMD_STS_SUCCESS )
     1295        {
     1296            printk("\n[ERROR] in %s : for command TX_CONNECT / socket[%x,%d] / thread[%x,%x]\n",
     1297            __FUNCTION__, pid, fdid, pid, trdid );
     1298            return -1;
     1299        }
     1300        else
     1301        {
     1302
     1303#if DEBUG_SOCKET_CONNECT
     1304cycle = (uint32_t)hal_get_cycles();
     1305if( DEBUG_SOCKET_CONNECT < cycle )
     1306printk("\n[%s] thread[%x,%x] exit for socket[%x,%d] / %s / cycle %d \n",
     1307__FUNCTION__, pid, trdid, pid, fdid, socket_state_str(socket_state),cycle );
     1308#endif
     1309             return 0;
     1310        }
     1311    }  // end TCP
     1312
     1313}  // end socket_connect()
     1314
     1315///////////////////////////////////
     1316int socket_close( xptr_t   file_xp,
     1317                  uint32_t fdid )
     1318{
     1319    uint32_t     socket_type;
     1320    uint32_t     socket_state;
     1321    uint32_t     nic_channel;
     1322    uint32_t     cmd_status;      // socket.tx_sts
     1323    bool_t       cmd_valid;       // socket.tx_valid
     1324    thread_t   * tx_server_ptr;   // local pointer on NIC_TX server thread
     1325    xptr_t       tx_server_xp;    // extended pointer on NIC_TX server thread
     1326    xptr_t       socket_lock_xp;  // extended pointer on socket lock
     1327
     1328    thread_t   * this      = CURRENT_THREAD;
     1329    xptr_t       client_xp = XPTR( local_cxy , this );
     1330    process_t  * process   = this->process;
     1331
     1332    // get pointer on socket descriptor
     1333    cxy_t        file_cxy    = GET_CXY( file_xp );
     1334    vfs_file_t * file_ptr    = GET_PTR( file_xp );
     1335    socket_t   * socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     1336
     1337assert( (hal_remote_l32( XPTR( file_cxy , &socket_ptr->fdid )) == fdid),
     1338"unconsistent file_xp & fdid arguments");
     1339
     1340#if DEBUG_SOCKET_CLOSE
     1341uint32_t cycle = (uint32_t)hal_get_cycles();
     1342pid_t    pid   = this->process->pid;
     1343if (DEBUG_SOCKET_CLOSE < cycle )
     1344printk("\n[%s] thread[%x,%x] enters for socket[%x,%d] / cycle %d\n",
     1345__FUNCTION__, pid, this->trdid, pid, fdid, cycle );
     1346#endif
     1347
     1348    // build extended pointer on lock protecting socket
     1349    socket_lock_xp = XPTR( file_cxy , &socket_ptr->lock );
     1350
     1351    // take socket lock
     1352    remote_queuelock_acquire( socket_lock_xp );
     1353
     1354    // check no previous TX command
     1355    if( (hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid )) == true) ||
     1356        (hal_remote_l64( XPTR( file_cxy , &socket_ptr->tx_client)) != XPTR_NULL) )
     1357    {
     1358        // release socket lock
     1359        remote_queuelock_release( socket_lock_xp );
     1360                   
     1361        printk("\n[ERROR] in %s : previous TX cmd on socket[%x,%d] / thread[%x,%x]\n",
     1362        __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     1363        return -1;
     1364    }
     1365
     1366    // get relevant socket infos
     1367    socket_type   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
     1368    nic_channel   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
     1369    socket_state  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     1370
     1371
     1372    // the actual close mechanism depends on socket type and state:
     1373    // UDP or TCP not connected : client thread directly destroy the socket descriptor
     1374    // TCP connected : client thread request TX server thread to make the TCP close handshake
     1375
     1376    if( socket_type == SOCK_DGRAM )                   // UDP
     1377    {
     1378
     1379#if DEBUG_SOCKET_CLOSE
     1380cycle = (uint32_t)hal_get_cycles();
     1381if( cycle > DEBUG_DEV_NIC_TX )
     1382printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / destroy socket / cycle %d\n",
     1383__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1384socket_state_str( socket_state ), cycle );
     1385#endif
     1386        // directly destroy socket
     1387        socket_destroy( file_xp );
     1388
     1389        return 0;
     1390    }
     1391    else if( (socket_state == TCP_STATE_BOUND) ||
     1392             (socket_state == TCP_STATE_LISTEN) ||
     1393             (socket_state == TCP_STATE_SYN_SENT) )   // TCP not connected
     1394    {
     1395
     1396#if DEBUG_SOCKET_CLOSE
     1397cycle = (uint32_t)hal_get_cycles();
     1398if( cycle > DEBUG_DEV_NIC_TX )
     1399printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / destroy socket / cycle %d\n",
     1400__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1401socket_state_str( socket_state ), cycle );
     1402#endif
     1403        // directly destroy socket
     1404        socket_destroy( file_xp );
     1405
     1406        return 0;
     1407    }
     1408    else                                             // TCP connected
     1409    {
     1410        // get pointers on NIC_TX[index] chdev
     1411        xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
     1412        chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
     1413        cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
     1414
     1415        // get pointers on NIC_TX[channel] server thread
     1416        tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
     1417        tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
     1418
     1419        // register command arguments in socket descriptor
     1420        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd    ), CMD_TX_CLOSE );
     1421        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ), client_xp );
     1422        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_valid  ), true );
     1423       
     1424        // unblock NIC_TX server thread
     1425        thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
     1426 
     1427        // release socket lock
     1428        remote_queuelock_release( socket_lock_xp );
     1429
     1430#if DEBUG_SOCKET_CLOSE
     1431cycle = (uint32_t)hal_get_cycles();
     1432if( DEBUG_SOCKET_CLOSE < cycle )
     1433printk("\n[%s] thread[%x,%x] socket[%x,%d] blocks on <IO> waiting close / cycle %d \n",
     1434__FUNCTION__, pid, this->trdid, pid, fdid, cycle );
     1435#endif
     1436        // block itself and deschedule
     1437        thread_block( client_xp , THREAD_BLOCKED_IO );
     1438        sched_yield( "blocked in close" );
     1439
     1440#if DEBUG_SOCKET_CLOSE
     1441cycle = (uint32_t)hal_get_cycles();
     1442if( DEBUG_SOCKET_CLOSE < cycle )
     1443printk("\n[%s] thread[%x,%x] socket[%x,%d] / resumes / cycle %d \n",
     1444__FUNCTION__, pid, this->trdid, pid, fdid, cycle );
     1445#endif
     1446        // take socket lock
     1447        remote_queuelock_acquire( socket_lock_xp );
     1448
     1449        // get socket state & command status
     1450        socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ) );
     1451        cmd_status   = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_sts) );
     1452        cmd_valid    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ) );
     1453
     1454assert( (((socket_state == TCP_STATE_CLOSED) || (cmd_status != CMD_STS_SUCCESS))
     1455         && (cmd_valid == false)),
     1456"illegal socket state when client thread resumes after TX_CLOSE\n"
     1457" socket_state = %s / cmd_status = %d / cmd_valid = %d\n",
     1458socket_state_str(socket_state), cmd_status, cmd_valid );
     1459
     1460        // reset socket.tx_client
     1461        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_client ) , XPTR_NULL );
     1462
     1463        if( cmd_status != CMD_STS_SUCCESS )  // error reported
     1464        {
     1465            printk("\n[ERROR] in %s for command TX_CLOSE / socket[%x,%d] / thread[%x,%x]\n",
     1466            __FUNCTION__, pid, fdid, pid, this->trdid );
     1467            return -1;
     1468        }
     1469        else                                 // success
     1470        {
     1471
     1472#if DEBUG_SOCKET_CLOSE
     1473cycle = (uint32_t)hal_get_cycles();
     1474if( DEBUG_SOCKET_CLOSE < cycle )
     1475printk("\n[%s] thread[%x,%x] socket[%x,%d] / destroy socket / cycle %d\n",
     1476__FUNCTION__, pid, this->trdid, pid, fdid, socket_state_str(socket_state) , cycle );
     1477#endif
     1478            // destroy socket
     1479            socket_destroy( file_xp );
     1480
     1481            return 0;
     1482        }
     1483    }   // end if TCP
     1484}  // end socket_close()
     1485
     1486////////////////////////////////////////////////////////////////////////////////////////
     1487// This static and blocking function is executed by an user thread calling one of the
     1488// four functions: socket_send() / socket_recv() / socket_sendto() / socket_recvfrom()
     1489// It can be used for both UDP and TCP sockets.
     1490////////////////////////////////////////////////////////////////////////////////////////
     1491// @ is_send   : send when true / receive when false.
     1492// @ fdid      : socket identifier.
     1493// @ u_buf     : pointer on user buffer in user space.
     1494// @ length    : number of bytes.
     1495// @ explicit  : explicit remote IP address and port when true.
     1496////////////////////////////////////////////////////////////////////////////////////////
     1497// Implementation note : The behavior is different for SEND & RECV
     1498// - For a SEND, the client thread checks that there is no TX command registered
     1499//   in the socket. It registers the command arguments in the socket descriptor
     1500//   (tx_client, tx_cmd, tx_buf, tx_len). Then the client thread unblocks the
     1501//   TX server thread from the BLOCKED_CLIENT condition, blocks itself on the
     1502//   BLOCKED_IO condition, and deschedules. It is unblocked by the TX server thread
     1503//   when the last byte has been sent (for UDP) or acknowledged (for TCP).
     1504//   When the client thread resumes, it reset the command in socket, and returns.
     1505// - For a RECV, the client thread checks that there is no RX command registered
     1506//   in the socket. It registers itself in socket (rx_client). It checks the status
     1507//   of the receive buffer. It the rx_buf is empty, it blocks on the BLOCKED_IO
     1508//   condition, and deschedules. It is unblocked by the RX server thread when an UDP
     1509//   packet or TCP segment has been writen in the rx_buf. When it resumes, it moves
     1510//   the available data from the rx_buf to the user buffer, reset its registration
     1511//   in socket (reset the rx_buf for an UDP socket), and returns.
     1512////////////////////////////////////////////////////////////////////////////////////////
     1513int socket_move_data( bool_t     is_send,
     1514                      uint32_t   fdid,
     1515                      uint8_t  * u_buf,
     1516                      uint32_t   length,
     1517                      bool_t     explicit,
     1518                      uint32_t   explicit_addr,
     1519                      uint32_t   explicit_port )
     1520{
     1521    vfs_inode_type_t    file_type;       // file descriptor type
     1522    socket_t          * socket_ptr;      // local pointer on socket descriptor
     1523    uint32_t            socket_state;    // current socket state
     1524    uint32_t            socket_type;     // socket type (UDP/TCP)
     1525    uint32_t            nic_channel;     // NIC channel for this socket
     1526    xptr_t              socket_lock_xp;  // extended pointer on socket lock
     1527    xptr_t              file_xp;         // extended pointer on file descriptor
     1528    vfs_file_t        * file_ptr;
     1529    cxy_t               file_cxy;
     1530    xptr_t              chdev_xp;        // extended pointer on NIC_TX[channel] chdev
     1531    chdev_t           * chdev_ptr;
     1532    cxy_t               chdev_cxy;
     1533    uint32_t            remote_addr;
     1534    uint32_t            remote_port;
     1535    uint32_t            buf_status;      // number of bytes in rx_buf
     1536    int32_t             moved_bytes;     // total number of moved bytes (fot return)
     1537    xptr_t              server_xp;       // extended pointer on NIC_TX / NIC_RX server thread
     1538    thread_t          * server_ptr;      // local pointer on NIC_TX / NIC_RX server thread
     1539    kmem_req_t          req;             // KCM request for TX kernel buffer
     1540    uint8_t           * tx_buf;          // kernel buffer for TX transfer
     1541    bool_t              cmd_valid;       // from socket descriptor
     1542    uint32_t            cmd_status;      // from socket descriptor
     1543    uint32_t            tx_todo;         // from socket descriptor
     1544
     1545    thread_t  * this    = CURRENT_THREAD;
     1546    process_t * process = this->process;
     1547
     1548    // build extended pointer on client thread
     1549    xptr_t client_xp = XPTR( local_cxy , this );
     1550
     1551    // get pointers on file descriptor identifying the socket
     1552    file_xp  = process_fd_get_xptr_from_local( process , fdid );
     1553    file_ptr = GET_PTR( file_xp );
     1554    file_cxy = GET_CXY( file_xp );
     1555
     1556    if( file_xp == XPTR_NULL )
     1557    {
     1558        printk("\n[ERROR] in %s : undefined fdid %d / thread%x,%x]\n",
     1559        __FUNCTION__, fdid , process->pid, this->trdid );
     1560        return -1;
     1561    }
     1562 
     1563    // get file type and socket pointer
     1564    file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
     1565
     1566    // get local pointer on socket
     1567    socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
     1568
     1569    // check file descriptor type
     1570    if( file_type != INODE_TYPE_SOCK )
     1571    {
     1572        printk("\n[ERROR] in %s : illegal file type %s / socket[%x,%d]\n",
     1573        __FUNCTION__, vfs_inode_type_str(file_type), process->pid, fdid );
     1574        return -1;
     1575    }
     1576
     1577    // build extended pointer on lock protecting socket
     1578    socket_lock_xp = XPTR( file_cxy , &socket_ptr->lock );
     1579
     1580    // take the socket lock
     1581    remote_queuelock_acquire( socket_lock_xp );
     1582
     1583    // get socket type, state, and channel
     1584    socket_type  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
     1585    socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
     1586    nic_channel  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
     1587
     1588    // handle the explicit remote address and port
     1589    if( socket_type == SOCK_DGRAM )                  // UDP socket
     1590    {
     1591        if( socket_state == UDP_STATE_UNBOUND )
     1592        {
     1593            // release socket lock
     1594            remote_queuelock_release( socket_lock_xp );
     1595                   
     1596            printk("\n[ERROR] in %s : SEND/RECV for socket[%x,%d] in state %s\n",
     1597            __FUNCTION__, process->pid, fdid, socket_state_str(socket_state) );
     1598            return -1;
     1599        }
     1600
     1601        if( explicit )
     1602        {
     1603            // update remote IP address and port into socket descriptor
     1604            hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_addr ), explicit_addr );
     1605            hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_port ), explicit_port );
     1606
     1607            // update socket state if required
     1608            if( socket_state == UDP_STATE_BOUND )
     1609            {
     1610                hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ), UDP_STATE_ESTAB );
     1611            }
     1612        }
     1613    }
     1614    else                                            // TCP socket
     1615    {
     1616        if( explicit )
     1617        {
     1618            // get remote IP address and port from socket descriptor
     1619            remote_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_addr ));
     1620            remote_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_port ));
     1621
     1622            if( (remote_addr != explicit_addr) || (remote_port != explicit_port) )
     1623            {
     1624                // release socket lock
     1625                remote_queuelock_release( socket_lock_xp );
     1626                   
     1627                printk("\n[ERROR] in %s : wrong expliciy access for socket[%x,%d]\n",
     1628                __FUNCTION__, process->pid, fdid );
     1629                return -1;
     1630            }
     1631        }
     1632    }
     1633
     1634    ///////////////////////////////////////////////////////
     1635    if( is_send )                       // TX_SEND command
     1636    {
     1637
     1638#if DEBUG_SOCKET_SEND
     1639uint32_t    cycle = (uint32_t)hal_get_cycles();
     1640if (DEBUG_SOCKET_SEND < cycle )
     1641printk("\n[%s] thread[%x,%x] received SEND command for socket[%x,%d] / length %d / cycle %d\n",
     1642__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, cycle );
     1643#endif
     1644        // check no previous TX command
     1645        if( (hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid )) == true) ||
     1646            (hal_remote_l64( XPTR( file_cxy , &socket_ptr->tx_client)) != XPTR_NULL) )
     1647        {
     1648            // release socket lock
     1649            remote_queuelock_release( socket_lock_xp );
     1650                   
     1651            printk("\n[ERROR] in %s : previous TX command / socket[%x,%d] / thread[%x,%x]\n",
     1652            __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     1653            return -1;
     1654        }
     1655
     1656        // allocate a temporary kernel buffer
     1657        req.type  = KMEM_KCM;
     1658        req.order = bits_log2( length );
     1659        req.flags = AF_NONE;
     1660        tx_buf    = kmem_alloc( &req ); 
     1661
     1662        if( tx_buf == NULL )
     1663        {
     1664            // release socket lock
     1665            remote_queuelock_release( socket_lock_xp );
     1666                   
     1667            printk("\n[ERROR] in %s : no memory for tx_buf / socket[%x,%d] / thread[%x,%x]\n",
     1668            __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     1669            return -1;
     1670        }
     1671
     1672        // copy data from user u_buf to kernel tx_buf   
     1673        hal_copy_from_uspace( XPTR( local_cxy , tx_buf ),
     1674                              u_buf,
     1675                              length );
     1676
     1677        // register command in socket descriptor
     1678        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client ) , client_xp );
     1679        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd    ) , CMD_TX_SEND );
     1680        hal_remote_spt( XPTR( file_cxy , &socket_ptr->tx_buf    ) , tx_buf );
     1681        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_len    ) , length );
     1682        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_todo   ) , length );
     1683        hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_valid  ) , true );
     1684
     1685        // release socket lock
     1686        remote_queuelock_release( socket_lock_xp );
     1687                   
     1688        // get pointers on relevant chdev
     1689        chdev_xp  = chdev_dir.nic_tx[nic_channel];
     1690        chdev_ptr = GET_PTR( chdev_xp );
     1691        chdev_cxy = GET_CXY( chdev_xp );
     1692
     1693        // get pointers on NIC_TX[channel] server thread
     1694        server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server ));
     1695        server_xp  = XPTR( chdev_cxy , server_ptr );
     1696
     1697        // unblocks the NIC_TX server thread
     1698        thread_unblock( server_xp , THREAD_BLOCKED_CLIENT );
     1699
     1700#if DEBUG_SOCKET_SEND   
     1701cycle = (uint32_t)hal_get_cycles();
     1702if( DEBUG_SOCKET_SEND < cycle )
     1703printk("\n[%s] thread[%x,%x] socket[%x,%d] register SEND => blocks on <IO> / cycle %d\n",
     1704__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     1705#endif
     1706        // client thread blocks itself and deschedules
     1707        thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     1708        sched_yield( "blocked in nic_io" );
     1709
     1710#if DEBUG_SOCKET_SEND   
     1711cycle = (uint32_t)hal_get_cycles();
     1712if( DEBUG_SOCKET_SEND < cycle )
     1713printk("\n[%s] thread[%x,%x] socket[%x,%d] for SEND resumes / cycle %d\n",
     1714__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     1715#endif
     1716        // take socket lock
     1717        remote_queuelock_acquire( socket_lock_xp );
     1718     
     1719        // get tx_valid, tx_todo, and tx_sts
     1720        tx_todo    = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_todo ));
     1721        cmd_valid  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_valid ));
     1722        cmd_status = hal_remote_l32( XPTR( file_cxy , &socket_ptr->tx_sts ));
     1723
     1724        // reset tx_client in socket descriptor
     1725        hal_remote_s64( XPTR( file_cxy , &socket_ptr->tx_client  ) , XPTR_NULL );
     1726
     1727        // release socket lock
     1728        remote_queuelock_release( socket_lock_xp );
     1729     
     1730// check SEND command completed when TX client thread resumes
     1731assert( (((tx_todo == 0) || (cmd_status != CMD_STS_SUCCESS)) && (cmd_valid == false)),
     1732"illegal socket state when client thread resumes after TX_SEND\n"
     1733" tx_todo = %d / tx_status = %d / tx_valid = %d\n",
     1734tx_todo, cmd_status, cmd_valid );
     1735
     1736        // release the tx_buf
     1737        req.ptr = tx_buf;
     1738        kmem_free( &req );
     1739
     1740        if( cmd_status != CMD_STS_SUCCESS )
     1741        {
     1742
     1743#if DEBUG_SOCKET_SEND
     1744cycle = (uint32_t)hal_get_cycles();
     1745if( DEBUG_SOCKET_RECV < cycle )
     1746printk("\n[%s] error %s for TX_SEND / socket[%x,%d] / thread[%x,%x]\n",
     1747__FUNCTION__, socket_cmd_sts_str(cmd_status), process->pid, fdid, process->pid, this->trdid );
     1748#endif
     1749            return -1;
     1750        }
     1751        else
     1752        {
     1753
     1754#if DEBUG_SOCKET_SEND
     1755cycle = (uint32_t)hal_get_cycles();
     1756if (DEBUG_SOCKET_SEND < cycle )
     1757printk("\n[%s] thread[%x,%x] success for SEND / socket[%x,%d] / length %d / cycle %d\n",
     1758__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, cycle );
     1759#endif
     1760            return length;
     1761        }
     1762
     1763    }  // end TX_SEND command
     1764
     1765    ////////////////////////////////////////////////////////
     1766    else                                 // RX_RECV command
     1767    {
     1768
     1769#if DEBUG_SOCKET_RECV
     1770uint32_t    cycle = (uint32_t)hal_get_cycles();
     1771if (DEBUG_SOCKET_SEND < cycle )
     1772printk("\n[%s] thread[%x,%x] received RECV command for socket[%x,%d] / length %d / cycle %d\n",
     1773__FUNCTION__, process->pid, this->trdid, process->pid, fdid, length, cycle );
     1774#endif
     1775        // check no previous RX command
     1776        if( (hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid )) == true) ||
     1777            (hal_remote_l64( XPTR( file_cxy , &socket_ptr->rx_client)) != XPTR_NULL) )
     1778        {
     1779            // release socket lock
     1780            remote_queuelock_release( socket_lock_xp );
     1781                   
     1782            printk("\n[ERROR] in %s : previous RX command on socket[%x,%d] / thread[%x,%x]\n",
     1783            __FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     1784            return -1;
     1785        }
     1786
     1787        // return EOF for a TCP socket not in ESTAB state
     1788        if( (socket_type == SOCK_STREAM ) && (socket_state != TCP_STATE_ESTAB) )
     1789        {
     1790            // release socket lock
     1791            remote_queuelock_release( socket_lock_xp );
     1792                   
     1793#if DEBUG_SOCKET_RECV 
     1794uint32_t cycle = (uint32_t)hal_get_cycles();
     1795if( DEBUG_SOCKET_RECV < cycle )
     1796printk("\n[%s] thread[%x,%x] socket[%x,%d] TCP connection closed / cycle %d\n",
     1797__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     1798#endif
     1799            return 0;
     1800        }
     1801        // build extended pointer on socket.rx_buf
     1802        xptr_t rx_buf_xp   = XPTR( file_cxy , &socket_ptr->rx_buf );
     1803
     1804        // get rx_buf status
     1805        buf_status = remote_buf_status( rx_buf_xp );
     1806
     1807        if( buf_status == 0 )
     1808        {
     1809            // registers RX_RECV command in socket descriptor
     1810            hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_cmd    ) , CMD_RX_RECV );
     1811            hal_remote_s64( XPTR( file_cxy , &socket_ptr->rx_client ) , client_xp );
     1812            hal_remote_s32( XPTR( file_cxy , &socket_ptr->rx_valid  ) , true );
     1813
     1814            // release socket lock
     1815            remote_queuelock_release( socket_lock_xp );
     1816
     1817#if DEBUG_SOCKET_RECV 
     1818uint32_t cycle = (uint32_t)hal_get_cycles();
     1819if( DEBUG_SOCKET_RECV < cycle )
     1820printk("\n[%s] thread[%x,%x] socket[%x,%d] rx_buf empty => blocks on <IO> / cycle %d\n",
     1821__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     1822#endif
     1823            // client thread blocks itself and deschedules
     1824            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
     1825            sched_yield( "blocked in nic_io" );
     1826
     1827#if DEBUG_SOCKET_RECV 
     1828cycle = (uint32_t)hal_get_cycles();
     1829if( DEBUG_SOCKET_RECV < cycle )
     1830printk("\n[%s] thread[%x,%x] socket[%x,%d] for RECV resumes / cycle %d\n",
     1831__FUNCTION__, process->pid, this->trdid, process->pid, fdid, cycle );
     1832#endif
     1833            // take socket lock
     1834            remote_queuelock_acquire( socket_lock_xp );
     1835
     1836            // get rx_sts and rx_buf status
     1837            cmd_valid  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_valid ));
     1838            cmd_status = hal_remote_l32( XPTR( file_cxy , &socket_ptr->rx_sts ));
     1839            buf_status = remote_buf_status( rx_buf_xp );
     1840       
     1841assert( (((buf_status != 0) || (cmd_status != CMD_STS_SUCCESS)) && (cmd_valid == false)),
     1842"illegal socket state when client thread resumes after RX_RECV\n"
     1843" buf_status = %d / rx_sts = %d / rx_valid = %d\n",
     1844buf_status , cmd_status , cmd_valid );
     1845
     1846            // reset rx_client in socket descriptor
     1847            hal_remote_s64( XPTR( file_cxy , &socket_ptr->rx_client  ) , XPTR_NULL );
     1848
     1849            // reset rx_buf for an UDP socket
     1850            if( socket_type == SOCK_DGRAM ) remote_buf_reset( rx_buf_xp );
     1851
     1852            // release socket lock
     1853            remote_queuelock_release( socket_lock_xp );
     1854
     1855            if( cmd_status == CMD_STS_EOF )           // EOF (remote close) reported
     1856            {
     1857
     1858#if DEBUG_SOCKET_RECV
     1859cycle = (uint32_t)hal_get_cycles();
     1860if( DEBUG_SOCKET_RECV < cycle )
     1861printk("\n[%s] EOF for RX_RECV / socket[%x,%d] / thread[%x,%x]\n",
     1862__FUNCTION__, process->pid, fdid, process->pid, this->trdid );
     1863#endif
     1864                return 0;
     1865            }
     1866            else if( cmd_status != CMD_STS_SUCCESS )   // other error reported
     1867            {
     1868
     1869#if DEBUG_SOCKET_RECV
     1870cycle = (uint32_t)hal_get_cycles();
     1871if( DEBUG_SOCKET_RECV < cycle )
     1872printk("\n[%s] error %s for RX_RECV / socket[%x,%d] / thread[%x,%x]\n",
     1873__FUNCTION__, socket_cmd_sts_str(cmd_status), process->pid, fdid, process->pid, this->trdid );
     1874#endif
     1875                return -1;
     1876            }
     1877
     1878        }
     1879
     1880        // number of bytes extracted from rx_buf cannot be larger than u_buf size
     1881        moved_bytes = ( length < buf_status ) ? length : buf_status;
     1882
     1883        // move data from kernel rx_buf to user u_buf
     1884        remote_buf_get_to_user( rx_buf_xp,
     1885                                u_buf,
     1886                                moved_bytes );
     1887#if DEBUG_SOCKET_SEND
     1888cycle = (uint32_t)hal_get_cycles();
     1889if (DEBUG_SOCKET_SEND < cycle )
     1890printk("\n[%s] thread[%x,%x] success for RECV / socket[%x,%d] / length %d / cycle %d\n",
     1891__FUNCTION__, process->pid, this->trdid, process->pid, fdid, moved_bytes, cycle );
     1892#endif
     1893        return moved_bytes;
     1894
     1895    }  // end RX_RECV command
     1896} // end socket_move_data()
     1897
     1898
     1899///////////////////////////////////
     1900int socket_send( uint32_t    fdid,
     1901                 uint8_t   * u_buf,
     1902                 uint32_t    length )
     1903{
     1904    int nbytes = socket_move_data( true,           // SEND
     1905                                   fdid,
     1906                                   u_buf,
     1907                                   length,
     1908                                   false, 0, 0 );  // no explicit remote socket
     1909    return nbytes;
     1910
     1911}  // end socket_send()
     1912
     1913/////////////////////////////////////
     1914int socket_sendto( uint32_t    fdid,
     1915                   uint8_t   * u_buf,
     1916                   uint32_t    length,
     1917                   uint32_t    remote_addr,
     1918                   uint32_t    remote_port )
     1919{
     1920    int nbytes = socket_move_data( true,          // SEND
     1921                                   fdid,
     1922                                   u_buf,
     1923                                   length,
     1924                                   true,          // explicit remote socket
     1925                                   remote_addr,
     1926                                   remote_port );
     1927    return nbytes;
     1928
     1929}  // end socket_sendto()
     1930
     1931///////////////////////////////////
     1932int socket_recv( uint32_t    fdid,
     1933                 uint8_t   * u_buf,
     1934                 uint32_t    length )
     1935{
     1936    int nbytes = socket_move_data( false,          // RECV
     1937                                   fdid,
     1938                                   u_buf,
     1939                                   length,
     1940                                   false, 0, 0 );  // no explicit remote socket
     1941    return nbytes;
     1942
     1943} // end socket_recv()
     1944
     1945
     1946///////////////////////////////////////
     1947int socket_recvfrom( uint32_t    fdid,
     1948                     uint8_t   * u_buf,
     1949                     uint32_t    length,
     1950                     uint32_t    remote_addr,
     1951                     uint32_t    remote_port )
     1952{
     1953    int nbytes = socket_move_data( false,         // RECV
     1954                                   fdid,
     1955                                   u_buf,
     1956                                   length,
     1957                                   true,          // explicit remote socket
     1958                                   remote_addr,
     1959                                   remote_port );
     1960    return nbytes;
     1961
     1962}  // end socket_recvfrom()
     1963
     1964////////////////////////////////////////////
     1965void socket_display( xptr_t       socket_xp,
     1966                     const char * func_str )
     1967{
     1968    socket_t * socket = GET_PTR( socket_xp );
     1969    cxy_t      cxy    = GET_CXY( socket_xp );
     1970
     1971    pid_t      pid         = hal_remote_l32( XPTR( cxy , &socket->pid ));
     1972    fdid_t     fdid        = hal_remote_l32( XPTR( cxy , &socket->fdid ));
     1973    uint32_t   state       = hal_remote_l32( XPTR( cxy , &socket->state ));
     1974    uint32_t   channel     = hal_remote_l32( XPTR( cxy , &socket->nic_channel ));
     1975    uint32_t   local_addr  = hal_remote_l32( XPTR( cxy , &socket->local_addr ));
     1976    uint32_t   local_port  = hal_remote_l32( XPTR( cxy , &socket->local_port ));
     1977    uint32_t   remote_addr = hal_remote_l32( XPTR( cxy , &socket->remote_addr ));
     1978    uint32_t   remote_port = hal_remote_l32( XPTR( cxy , &socket->remote_port ));
     1979    uint32_t   tx_valid    = hal_remote_l32( XPTR( cxy , &socket->tx_valid ));
     1980    uint32_t   tx_cmd      = hal_remote_l32( XPTR( cxy , &socket->tx_cmd ));
     1981    uint32_t   tx_sts      = hal_remote_l32( XPTR( cxy , &socket->tx_sts ));
     1982    uint32_t   tx_len      = hal_remote_l32( XPTR( cxy , &socket->tx_len ));
     1983    uint32_t   tx_todo     = hal_remote_l32( XPTR( cxy , &socket->tx_todo ));
     1984    uint32_t   tx_una      = hal_remote_l32( XPTR( cxy , &socket->tx_una ));         
     1985    uint32_t   tx_nxt      = hal_remote_l32( XPTR( cxy , &socket->tx_nxt ));         
     1986    uint32_t   tx_wnd      = hal_remote_l32( XPTR( cxy , &socket->tx_wnd ));         
     1987    uint32_t   rx_valid    = hal_remote_l32( XPTR( cxy , &socket->rx_valid ));
     1988    uint32_t   rx_cmd      = hal_remote_l32( XPTR( cxy , &socket->rx_cmd ));
     1989    uint32_t   rx_sts      = hal_remote_l32( XPTR( cxy , &socket->rx_sts ));
     1990    uint32_t   rx_nxt      = hal_remote_l32( XPTR( cxy , &socket->rx_nxt ));         
     1991    uint32_t   rx_wnd      = hal_remote_l32( XPTR( cxy , &socket->rx_wnd ));         
     1992    uint32_t   rx_irs      = hal_remote_l32( XPTR( cxy , &socket->rx_irs ));         
     1993
     1994    if( func_str == NULL )
     1995    {
     1996        printk("\n****** socket[%x,%d] / xptr[%x,%x]*****\n",
     1997        pid, fdid, cxy, socket );
     1998    }
     1999    else
     2000    {
     2001        printk("\n***** socket[%x,%d] / xptr[%x,%x] / from %s *****\n",
     2002        pid, fdid, cxy, socket, func_str );
     2003    }
     2004    printk(" - state %s / channel %d\n"
     2005           " - local_addr %x / local_port %x\n"
     2006           " - remote_addr %x / remote_port %x\n"
     2007           " - tx_valid %d (%s) / tx_sts %d / tx_len %x / tx_todo %x\n"
     2008           " - tx_una %x / tx_nxt %x / tx_wnd %x\n"
     2009           " - rx_valid %d (%s) / rx_sts %d\n"
     2010           " - rx_nxt %x / rx_wnd %x / rx_irs %x\n",
     2011           socket_state_str(state), channel ,
     2012           local_addr, local_port,
     2013           remote_addr, remote_port,
     2014           tx_valid, socket_cmd_type_str(tx_cmd), tx_sts, tx_len, tx_todo,
     2015           tx_una, tx_nxt, tx_wnd,
     2016           rx_valid, socket_cmd_type_str(rx_cmd), rx_sts,
     2017           rx_nxt, rx_wnd, rx_irs );
     2018
     2019}  // end socket_display()
     2020
     2021
     2022
     2023
     2024
  • trunk/kernel/kern/ksocket.h

    r657 r662  
    11/*
    2  * socket.c - socket API implementation.
    3  *
    4  * Authors  Alain Greiner   (2016,2017,2018,2019,2020)
     2 * ksocket.h - kernel socket descriptor and API definition.
     3 * 
     4 * Authors  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
    77 *
    8  * This file is part of ALMOS-MKH.
    9  *
    10  * ALMOS-MKH.is free software; you can redistribute it and/or modify it
     8 * This file is part of ALMOS-MKH
     9 *
     10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
    1111 * under the terms of the GNU General Public License as published by
    1212 * the Free Software Foundation; version 2.0 of the License.
    1313 *
    14  * ALMOS-MKH.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
    1515 * WITHOUT ANY WARRANTY; without even the implied warranty of
    1616 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     
    1818 *
    1919 * 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,
     20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
    2121 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
    2222 */
    2323
     24#ifndef _KSOCKET_H_
     25#define _KSOCKET_H_
     26
    2427#include <kernel_config.h>
    2528#include <hal_kernel_types.h>
    26 #include <hal_remote.h>
    27 #include <shared_socket.h>
    28 #include <process.h>
     29#include <xlist.h>
    2930#include <remote_buf.h>
    30 #include <printk.h>
    31 #include <kmem.h>
    32 #include <thread.h>
    33 #include <vfs.h>
    34 #include <socket.h>
    35 
    36 //////////////////////////////////////////////////////////////////////////////////////
    37 // Extern global variables
    38 //////////////////////////////////////////////////////////////////////////////////////
    39 
    40 extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
    41 
    42 //////////////////////////////////////
    43 char * socket_cmd_str( uint32_t type )
     31#include <remote_busylock.h>
     32
     33/*****************************************************************************************
     34 * This structure defines a kernel socket descriptor, used for both UDP or TCP sockets.
     35 * A socket is a private resource used by a most two user threads : one TX client
     36 * thread to send packets, and one RX client thread, to receive packets. The TX client
     37 * thread and the RX client thread can be the same thread.
     38 *
     39 * When the Network Interface Controller contains several channels, the set of all
     40 * existing sockets is split in as many subsets as the number of NIC channels, in order
     41 * to parallelize the transfers. The distribution key defining the channel index
     42 * is computed from the (remote_addr/remote_port) couple: by the NIC hardware for the
     43 * RX packets; by the software for the TX packets, using a dedicated NIC driver function.
     44 * All sockets that have the same key share the same channel, and each socket is
     45 * therefore linked to two chdevs : NIC_TX[key] & NIC_RX[key].
     46 * The socket allows the NIC-TX and NIC_RX server threads to access various buffers:
     47 * - the kernel "tx_buf" buffer contains the data to be send by the TX server thread.
     48 *   It is dynamically allocated, and used as retransmission buffer when required.
     49 * - the kernel "rx_buf" buffer contains the data received by the RX server thread.
     50 *   It is allocated in socket and handled as a single writer / single reader FIFO.
     51 * - the kernel "r2t" buffer allows the RX server thread to make direct requests
     52 *   to the associated TX server (mainly used to handle the TCP ACKs).
     53 * - the kernel "crq" buffer allows to store concurrent remote client connect requests
     54 *   to a local server socket. It is allocated in socket.
     55 *
     56 * The synchronisation mechanism between the client threads and the server threads
     57 * is different for the TX and RX directions:
     58 *
     59 * 1) TX stream
     60 *
     61 * - The internal API between the TX client thread and the NIC_TX server thread defines
     62 *   four command types, stored in the "tx_cmd" variable of the socket descriptor:
     63 *   . SOCKET_TX_CONNECT : TCP client request to start the 3 steps connection handshake.
     64 *   . SOCKET_TX_ACCEPT  : TCP server request to accept one pending connection request.
     65 *   . SOCKET_TX_SEND    : local (UDP/TCP) request to send data to a remote (UDP/TCP).
     66 *   . SOCKET_TX_CLOSE   : local TCP socket request remote TCP socket to close connection.
     67 * - All commands are blocking for the TX client thread: to make a command, the TX client
     68 *   registers the command type in the socket "tx_cmd",field, set the "tx_valid" field,
     69 *   reset the "tx_error" field, and registers itself in the "tx_client" field.
     70 *   Then, it unblocks the TX server thread from the BLOCKED_CLIENT condition, blocks itself
     71 *   on the BLOCKED_IO condition, and deschedules. For a SEND, the "tx_buf" kernel buffer
     72 *   is dynamicaly allocated by the client thread, that copies the payload from the user
     73 *   buffer to this kernel buffer, that is used as retransmission buffer, when required.
     74 * - A command is valid for the TX server when the socket descriptor "tx_valid" is true.
     75 *   For a SEND command, the "tx_valid" is reset by the NIC_TX server when the last byte has
     76 *   been sent, but the TX client thread is unblocked by the NIC_RX server thread only when
     77 *   the last byte has been acknowledged, or to report an error.
     78 *   For the CONNECT, ACCEPT and CLOSE commands, the "tx_valid" is reset by the NIC_TX server
     79 *   when the first segment of the handshake has been sent, but the TX client thread is
     80 *   unblocked by the NIC_RX server thread only when the handshake is actually completed.
     81 *   The TX server thread is acting as a multiplexer. It scans the list of attached sockets,
     82 *   to sequencially handle the valid commands: one UDP packet or TCP segment per iteration.
     83 *   The TX server blocks and deschedules on the BLOCKED_CLIENT condition when there is
     84 *   no more valid TX command or R2T request registered in any socket. It is unblocked
     85 *   from BLOCKED_CLIENT by a client thread registering a TX command, or by the RX server
     86 *   thread registering a R2T request. The TX server thread signals an error to the TX client
     87 *   thread using the "tx_error" field in socket descriptor.
     88 *   When "tx_valid" or "r2t_valid" are true, the TX server thread build and send an UDP
     89 *   packet or TCP segment. A single SEND command can require a large number of TCP
     90 *   segments to move a big data buffer.
     91 *   This TX server thread blocks and deschedules on the BLOCKED_ISR condition when there
     92 *   the NIC_RX queue is full . It is unblocked by the hardware NIC_TX_ISR.
     93 * - In order to detect and report error for multiple simultaneous TX accesses to the same
     94 *   socket, the client thread makes a double check before posting a new TX command :
     95 *   the "tx_valid" field must be false, and the "tx_client" field must be XPTR_NULL.
     96 *   The "tx_valid" field is reset by the TX server thread, and the "tx_client"
     97 *   field is reset by the TX client thread itself, when it resumes after a TX command.
     98 *   . For a SEND command on an UDP socket, the TX server thread reset "tx_valid" and
     99 *     unblocks the TX client thread as soon as the last data byte has been sent.
     100 *   . For a SEND command on a TCP socket, the TX server thread reset "tx_valid" when the
     101 *     last data byte has been sent, but the TX client thread is unblocked by the TX server
     102 *     only when the last data byte has been acknowledged by the remote socket.
     103 *   . For the CONNECT or ACCEPT commands, the "tx_valid" flag is reset and the TX client
     104 *     thread is unblocked by the RX server thread only when the command is completed,
     105 *     and the local TCP socket is actually in the ESTAB state.
     106 *   . For a CLOSE command, the "tx_valid" flag is reset, and the TX client thread is
     107 *     unblocked by the RX server thread only when the remote socket is disconnected.
     108 *
     109 * 2) RX stream
     110 *
     111 * - The internal API between the RX client thread and the RX server thread defines two
     112 *   command types stored in the rx_cmd variable of the socket descriptor:
     113 *   . SOCKET_RX_ACCEPT : TCP server request a connection request from CRQ queue.
     114 *   . SOCKET_RX_RECV   : local (UDP/TCP) socket expect data from a remote (UDP/TCP).
     115 *   For the RECV command the communication is done through the "rx_buf" buffer,
     116 *   attached to the socket, and handled as a single-writer / single reader-FIFO.
     117 *   For the ACCEPT command the communication is done through the CRQ buffer, attached
     118 *   to the socket, and handled as a single-writer / single reader-FIFO.
     119 *   These two commands are blocking for the RX client thread as long as the buffer is
     120 *   empty. The client thread set the socket "rx_valid" field, reset the "rx_error" field,
     121 *   registers itself in the "rx_client" field, and  blocks on the BLOCKED_IO condition.
     122 * - The RX server thread is acting as a demultiplexor: it handle one received TCP segment,
     123 *   or UDP packet per iteration in the loop on the NIC_RX queue, and moves the data to
     124 *   the relevant buffer of the socket matching the packet. It discard packets that don't
     125 *   match a registered socket. When a client thread is registered in the socket descriptor,
     126 *   the RX server thread reset the "rx_valid" field and unblocks the RX client thread from
     127 *   the BLOCKED_IO condition as soon as there is data available in the "rx_buf".
     128 *   This RX server thread blocks and deschedules on the BLOCKED_ISR condition when there
     129 *   is no more packets in the NIC_RX queue. It is unblocked by the hardware NIC_RX_ISR.
     130 * - In order to detect and report error for multiple simultaneous RX accesses to the same
     131 *   socket, the RX client thread makes a double check before posting a new RX command :
     132 *   the "rx_valid" field must be false, and the "rx_client" field must be XPTR_NULL.
     133 *   The "rx_valid" field is reset by the RX server thread, and the "rx_client"
     134 *   field is reset by the RX client thread itself, when it resumes after an RX command.
     135 *
     136 * 3) R2T queue
     137 *
     138 * To implement the TCP "3 steps handshake" protocol for connection or to send RST,
     139 * the RX server thread can directly request the associated TX server thread to send
     140 * control packets in  the TX stream, using a dedicate R2T (RX to TX) FIFO stored in
     141 * the socket descriptor. Each R2T request occupy one byte in this R2T queue.
     142 *
     143 * 4) CRQ queue
     144 *
     145 * The remote CONNECT requests received by a TCP socket (SYN segments) are stored in a
     146 * dedicated CRQ FIFO stored in the local socket descriptor. These requests are consumed
     147 * by the local client thread executing an ACCEPT.
     148 * Each CRQ request occupy sizeof(connect_request_t) bytes in this CRQ queue.
     149 * The connect_request_t structure containing the request arguments is defined below.
     150 *
     151 * Note : the socket domains and types are defined in the "shared_socket.h" file.
     152 ****************************************************************************************/
     153
     154/*****************************************************************************************
     155 * This enum defines the set of commands that can be registered in the socket
     156 * by the TX & RX client threads to be executed by the NIC_TX & NIC_TX server threads.
     157 ****************************************************************************************/
     158typedef enum socket_cmd_type_e
    44159{
    45     switch( type )
    46     {
    47         case SOCKET_TX_CONNECT  : return "CONNECT";
    48         case SOCKET_TX_SEND     : return "SEND";
    49         case SOCKET_TX_CLOSE    : return "CLOSE";
    50 
    51         default:                return "undefined";
    52     }
     160    CMD_TX_CONNECT      = 20,         /*! request a SYN segment     (TCP only)          */
     161    CMD_TX_ACCEPT       = 21,         /*! request a SYN-ACK segment (TCP only)          */
     162    CMD_TX_CLOSE        = 22,         /*! request a RST segment     (TCP only)          */
     163    CMD_TX_SEND         = 23,         /*! request to send data      (TCP or UDP)        */
     164
     165    CMD_RX_ACCEPT       = 30,         /*! wait request from CRQ     (TCP only)          */
     166    CMD_RX_RECV         = 31,         /*! wait DATA from rx_buf     (TCP or UDP)        */
    53167}
    54    
    55 /////////////////////////////////////////
    56 char * socket_state_str( uint32_t state )
     168socket_cmd_type_t;
     169
     170/*****************************************************************************************
     171 * This enum defines the set of command status that can be returned by the NIC_RX and
     172 * NIC_TX server threads to the TX & RX client threads.
     173 * The success must be signaled by the null value / the various failure cases are
     174 * signaled by a non-null value.
     175 ****************************************************************************************/
     176typedef enum socket_cmd_sts_e
    57177{
    58     switch( state )
    59     {
    60         case UDP_STATE_UNBOUND    : return "UDP_UNBOUND";
    61         case UDP_STATE_BOUND      : return "UDP_BOUND";
    62         case UDP_STATE_CONNECT    : return "UDP_CONNECT";
    63 
    64         case TCP_STATE_UNBOUND    : return "TCP_UNBOUND";
    65         case TCP_STATE_BOUND      : return "TCP_BOUND";
    66         case TCP_STATE_LISTEN     : return "TCP_LISTEN";
    67         case TCP_STATE_SYN_SENT   : return "TCP_SYN_SENT";
    68         case TCP_STATE_SYN_RCVD   : return "TCP_SYN_RCVD";
    69         case TCP_STATE_ESTAB      : return "TCP_ESTAB";
    70         case TCP_STATE_FIN_WAIT1  : return "TCP_FIN_WAIT1";
    71         case TCP_STATE_FIN_WAIT2  : return "TCP_FIN_WAIT2";
    72         case TCP_STATE_CLOSING    : return "TCP_CLOSING";
    73         case TCP_STATE_TIME_WAIT  : return "TCP_TIME_WAIT";
    74         case TCP_STATE_CLOSE_WAIT : return "TCP_CLOSE_WAIT";
    75         case TCP_STATE_LAST_ACK   : return "TCP_LAST_ACK";
    76 
    77         default:                    return "undefined";
    78     }
     178    CMD_STS_SUCCESS     =  0,
     179    CMD_STS_EOF         =  1,
     180    CMD_STS_RST         =  2,
     181    CMD_STS_BADACK      =  3,
     182    CMD_STS_BADSTATE    =  4,
     183    CMD_STS_BADCMD      =  5,
    79184}
    80 
    81 ///////////////////////////////////////
    82 error_t socket_create( cxy_t       cxy,
    83                        uint32_t    domain,
    84                        uint32_t    type,
    85                        socket_t ** socket_ptr,
    86                        uint32_t  * fdid_ptr )
     185socket_cmd_sts_t;
     186
     187/*****************************************************************************************
     188 * This enum defines the set of tates for an UDP socket.
     189 ****************************************************************************************/
     190typedef enum udp_socket_state_e
    87191{
    88     uint32_t    fdid;
    89 
    90     thread_t  * this    = CURRENT_THREAD;
    91     process_t * process = this->process;
    92 
    93     kmem_req_t     req;
    94     socket_t     * socket;
    95     vfs_file_t   * file;
    96     uint32_t       state;
    97     error_t        error;
    98 
    99     // allocate memory for socket descriptor
    100     req.type   = KMEM_KCM;
    101     req.order  = bits_log2( sizeof(socket_t) );
    102     req.flags  = AF_ZERO;
    103     socket     = kmem_remote_alloc( cxy , &req );
    104 
    105     if( socket == NULL )
    106     {
    107         printk("\n[ERROR] in %s : cannot allocate socket descriptor / thread[%x,%x]\n",
    108         __FUNCTION__, process->pid, this->trdid );
    109         return -1;
    110     }
    111 
    112     // allocate memory for rx_buf buffer
    113     error = remote_buf_create( XPTR( cxy , &socket->rx_buf ),
    114                                NIC_RX_BUF_SIZE );
    115 
    116     if( error )
    117     {
    118         printk("\n[ERROR] in %s : cannot allocate rx_buf / thread[%x,%x]\n",
    119         __FUNCTION__, process->pid, this->trdid );
    120         req.type = KMEM_KCM;
    121         req.ptr  = socket;
    122         kmem_remote_free( cxy , &req );
    123         return -1;
    124     }
    125 
    126     // allocate memory for r2tq queue
    127     error = remote_buf_create( XPTR( cxy , &socket->r2tq ),
    128                                NIC_R2T_QUEUE_SIZE );
    129     if( error )
    130     {
    131         printk("\n[ERROR] in %s : cannot allocate R2T queue / thread[%x,%x]\n",
    132         __FUNCTION__, process->pid, this->trdid );
    133         remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
    134         req.type = KMEM_KCM;
    135         req.ptr  = socket;
    136         kmem_remote_free( cxy , &req );
    137         return -1;
    138     }
    139 
    140     // allocate memory for crqq queue
    141     error = remote_buf_create( XPTR( cxy , &socket->crqq ),
    142                                NIC_CRQ_QUEUE_SIZE * sizeof(sockaddr_t) );
    143     if( error )
    144     {
    145         printk("\n[ERROR] in %s : cannot allocate CRQ queue / thread[%x,%x]\n",
    146         __FUNCTION__, process->pid, this->trdid );
    147         remote_buf_destroy( XPTR( cxy , &socket->r2tq ) );
    148         remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
    149         req.type = KMEM_KCM;
    150         req.ptr  = socket;
    151         kmem_remote_free( cxy , &req );
    152         return -1;
    153     }
    154 
    155     //  allocate memory for file descriptor
    156         req.type  = KMEM_KCM;
    157         req.order = bits_log2( sizeof(vfs_file_t) );
    158     req.flags = AF_ZERO;
    159         file      = kmem_remote_alloc( cxy , &req );
    160 
    161     if( file == NULL )
    162     {
    163         printk("\n[ERROR] in %s : cannot allocate file descriptor / thread[%x,%x]\n",
    164         __FUNCTION__, process->pid, this->trdid );
    165         remote_buf_destroy( XPTR( cxy , &socket->crqq ) );
    166         remote_buf_destroy( XPTR( cxy , &socket->r2tq ) );
    167         remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
    168         req.type = KMEM_KCM;
    169         req.ptr  = socket;
    170         kmem_remote_free( cxy , &req );
    171         return -1;
    172     }
    173    
    174     // get an fdid value, and register file descriptor in fd_array[]
    175     error = process_fd_register( process->ref_xp,
    176                                  XPTR( cxy , file ),
    177                                  &fdid );
    178     if ( error )
    179     {
    180         printk("\n[ERROR] in %s : cannot register file descriptor / thread[%x,%x]\n",
    181         __FUNCTION__, process->pid, this->trdid );
    182         req.type = KMEM_KCM;
    183         req.ptr  = file;
    184         kmem_free( &req );
    185         remote_buf_destroy( XPTR( cxy , &socket->crqq ) );
    186         remote_buf_destroy( XPTR( cxy , &socket->r2tq ) );
    187         remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
    188         req.ptr  = socket;
    189         kmem_free( &req );
    190         return -1;
    191     }
    192     state = (type == SOCK_STREAM) ? TCP_STATE_UNBOUND : UDP_STATE_UNBOUND;
    193 
    194     // initialise socket descriptor
    195     hal_remote_s32( XPTR( cxy , &socket->domain    ) , domain );
    196     hal_remote_s32( XPTR( cxy , &socket->type      ) , type );
    197     hal_remote_s32( XPTR( cxy , &socket->pid       ) , process->pid );
    198     hal_remote_s32( XPTR( cxy , &socket->state     ) , state );
    199     hal_remote_s64( XPTR( cxy , &socket->tx_client ) , XPTR_NULL );
    200     hal_remote_s64( XPTR( cxy , &socket->rx_client ) , XPTR_NULL );
    201 
    202     // initialize file descriptor
    203     hal_remote_s32( XPTR( cxy , &file->type        ) , INODE_TYPE_SOCK );
    204     hal_remote_spt( XPTR( cxy , &file->socket      ) , socket );
    205     hal_remote_s32( XPTR( cxy , &file->refcount    ) , 1 );
    206 
    207     remote_rwlock_init( XPTR( cxy , &file->lock ) , LOCK_VFS_FILE );
    208    
    209     // return success
    210     *socket_ptr = socket;
    211     *fdid_ptr   = fdid;
    212 
    213     return 0;
    214 
    215 }  // end socket_create
    216 
    217 ////////////////////////////////////
    218 void socket_destroy( uint32_t fdid )
     192    UDP_STATE_UNBOUND    = 0x00,
     193    UDP_STATE_BOUND      = 0x01,
     194    UDP_STATE_ESTAB      = 0x02,
     195}
     196udp_socket_state_t;
     197
     198/*****************************************************************************************
     199 * This enum defines the set of tates for an TCP socket.
     200 ****************************************************************************************/
     201typedef enum tcp_socket_state_e
    219202{
    220     uint32_t            type;
    221     socket_t          * socket;
    222     kmem_req_t          req;
    223 
    224     thread_t  * this    = CURRENT_THREAD;
    225     process_t * process = this->process;
    226 
    227     // get pointers on file descriptor
    228     xptr_t       file_xp  = process_fd_get_xptr( process , fdid );
    229     vfs_file_t * file     = GET_PTR( file_xp );
    230     cxy_t        cxy      = GET_CXY( file_xp );
    231 
    232     type   = hal_remote_l32( XPTR( cxy , &file->type ) );
    233     socket = hal_remote_lpt( XPTR( cxy , &file->socket ) );
    234 
    235 // check file descriptor pointer
    236 assert( (file_xp != XPTR_NULL), "illegal fdid\n" );
    237 
    238 // check file descriptor type
    239 assert( (type == INODE_TYPE_SOCK), "illegal file type\n" );
    240 
    241     // remove the file descriptor from the process
    242     process_fd_remove( process->owner_xp , fdid );
    243 
    244     // release memory allocated for file descriptor
    245     req.type = KMEM_KCM;
    246     req.ptr  = file;
    247     kmem_remote_free( cxy , &req );
    248 
    249     // release memory allocated for buffers attached to socket descriptor
    250     remote_buf_destroy( XPTR( cxy , &socket->crqq ) );
    251     remote_buf_destroy( XPTR( cxy , &socket->r2tq ) );
    252     remote_buf_destroy( XPTR( cxy , &socket->rx_buf ) );
    253 
    254     // release memory allocated for socket descriptor
    255     req.type = KMEM_KCM;
    256     req.ptr  = socket;
    257     kmem_remote_free( cxy , &req );
    258 
    259 }  // end socket_destroy()
    260 
    261 /////////////////////////////////////////////////
    262 void socket_link_to_servers( xptr_t    socket_xp,
    263                              uint32_t  nic_channel )
     203    TCP_STATE_UNBOUND    = 0x10,
     204    TCP_STATE_BOUND      = 0x11,
     205    TCP_STATE_LISTEN     = 0x12,
     206    TCP_STATE_SYN_SENT   = 0x13,
     207    TCP_STATE_SYN_RCVD   = 0x14,
     208    TCP_STATE_ESTAB      = 0x15,
     209    TCP_STATE_FIN_WAIT1  = 0x16,
     210    TCP_STATE_FIN_WAIT2  = 0x17,
     211    TCP_STATE_CLOSING    = 0x18,
     212    TCP_STATE_TIME_WAIT  = 0x19,
     213    TCP_STATE_CLOSE_WAIT = 0x1A,
     214    TCP_STATE_LAST_ACK   = 0x1B,
     215    TCP_STATE_CLOSED     = 0x1C,
     216}
     217tcp_socket_state_t;
     218
     219/*****************************************************************************************
     220 * This structure defines one connection request, registered in the CRQ queue.
     221 ****************************************************************************************/
     222typedef struct connect_request_s
    264223{
    265     cxy_t      socket_cxy = GET_CXY( socket_xp );
    266     socket_t * socket_ptr = GET_PTR( socket_xp );
    267 
    268     // get pointers on NIC_TX[index] chdev
    269     xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
    270     chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
    271     cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
    272 
    273     // build extended pointers on root of sockets attached to NIC_TX[channel] chdev
    274     xptr_t    tx_root_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_root );
    275     xptr_t    tx_lock_xp = XPTR( tx_chdev_cxy , &tx_chdev_ptr->wait_lock );
    276 
    277     // register socket in the NIC_TX[channel] chdev clients queue
    278     remote_rwlock_wr_acquire( tx_lock_xp );
    279     xlist_add_last( tx_root_xp , XPTR( socket_cxy , &socket_ptr->tx_list ) );
    280     remote_rwlock_wr_release( tx_lock_xp );
    281 
    282     // get pointers on NIC_RX[index] chdev
    283     xptr_t    rx_chdev_xp  = chdev_dir.nic_rx[nic_channel];
    284     chdev_t * rx_chdev_ptr = GET_PTR( rx_chdev_xp );
    285     cxy_t     rx_chdev_cxy = GET_CXY( rx_chdev_xp );
    286 
    287     // build extended pointer on root of sockets attached to NIC_TX[channel] chdev
    288     xptr_t    rx_root_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_root );
    289     xptr_t    rx_lock_xp = XPTR( rx_chdev_cxy , &rx_chdev_ptr->wait_lock );
    290 
    291     // register socket in the NIC_RX[channel] chdev clients queue
    292     remote_rwlock_wr_acquire( rx_lock_xp );
    293     xlist_add_last( rx_root_xp , XPTR( socket_cxy , &socket_ptr->rx_list ) );
    294     remote_rwlock_wr_release( rx_lock_xp );
    295 
    296 }  // end socket_link_to_server()
    297 
    298 
     224    uint32_t          addr;          /* requesting socket IP address                   */
     225    uint32_t          port;          /* requesting socket port number                  */
     226    uint32_t          iss;           /* requesting socket initial sequence number      */
     227    uint32_t          window;        /* requesting socket receive window               */
     228}         
     229connect_request_t;
     230
     231/*****************************************************************************************
     232 * This structure defines the socket descriptor.
     233 ****************************************************************************************/
     234typedef struct socket_s
     235{
     236    remote_queuelock_t lock;         /*! lock protecting socket state                  */
     237    pid_t              pid;          /*! owner process identifier                      */
     238    uint32_t           fdid;         /*! associated file descriptor index              */
     239    uint32_t           domain;       /*! domain : AF_LOCAL / AF_INET                   */
     240    uint32_t           type;         /*! type : SOCK_DGRAM / SOCK_STREAM               */
     241    uint32_t           state;        /*! socket state (see above)                      */
     242    uint32_t           local_addr;   /*! local  socket IP address                      */
     243    uint32_t           remote_addr;  /*! remote socket IP address                      */
     244    uint32_t           local_port;   /*! local  socket port number                     */
     245    uint32_t           remote_port;  /*! remote socket port number                     */
     246    uint32_t           nic_channel;  /*! derived from (remote_addr,remote_port)        */
     247
     248    xlist_entry_t      tx_list;      /*! all sockets attached to same NIC_TX channel   */
     249    xptr_t             tx_client;    /*! extended pointer on current TX client thread  */
     250    bool_t             tx_valid;     /*! TX command valid                              */
     251    socket_cmd_type_t  tx_cmd;       /*! TX command (CONNECT / ACCEPT / SEND / CLOSE)  */
     252    uint32_t           tx_sts;       /*! signal a TX command success / failure         */
     253    uint8_t         *  tx_buf;       /*! pointer on TX data buffer in kernel space     */
     254    uint32_t           tx_len;       /*! number of data bytes for a SEND command       */
     255    uint32_t           tx_todo;      /*! number of bytes not yet sent                  */
     256    xlist_entry_t      tx_temp;      /*! temporary list of sockets (root in TX chdev)  */
     257
     258    xlist_entry_t      rx_list;      /*! all sockets attached to same NIC_RX channel   */
     259    xptr_t             rx_client;    /*! extended pointer on current RX client thread  */
     260    bool_t             rx_valid;     /*! RX command valid                              */
     261    socket_cmd_type_t  rx_cmd;       /*! RX command ( ACCEPT / RECV )                  */
     262    uint32_t           rx_sts;       /*! signal a RX command success / failure         */
     263    remote_buf_t       rx_buf;       /*! embedded receive buffer descriptor            */
     264
     265    remote_buf_t       r2tq;         /*! RX_to_TX requests queue descriptor            */
     266    remote_buf_t       crqq;         /*! connection requests queue descriptor          */
     267
     268    /* the following fields defines the TCB (only used for a TCP connection)           */
     269
     270    uint32_t           tx_nxt;       /*! next byte to send in TX_data stream           */
     271    uint32_t           tx_wnd;       /*! number of acceptable bytes in TX_data stream  */
     272    uint32_t           tx_una;       /*! first unack byte in TX_data stream            */
     273    uint32_t           rx_nxt;       /*! next expected byte in RX_data stream          */
     274    uint32_t           rx_wnd;       /*! number of acceptable bytes in RX_data stream  */
     275    uint32_t           rx_irs;       /*! initial sequence number in RX_data stream     */
     276}
     277socket_t;
     278
     279/****************************************************************************************
     280 * This function returns a printable string for a socket domain.
     281 ****************************************************************************************
     282 * domain   :  AF_INET / AF_LOCAL
     283 ***************************************************************************************/
     284char * socket_domain_str( uint32_t domain );
     285
     286/****************************************************************************************
     287 * This function returns a printable string for a socket type.
     288 ****************************************************************************************
     289 * type   :  SOCK_DGRAM / SOCK_STREAM
     290 ***************************************************************************************/
     291char * socket_type_str( uint32_t type );
     292
     293/****************************************************************************************
     294 * This function returns a printable string for an UDP or TCP socket state.
     295 ****************************************************************************************
     296 * state  :  UDP_STATE_*** / TCP_STATE***
     297 ***************************************************************************************/
     298char * socket_state_str( uint32_t state );
     299
     300/****************************************************************************************
     301 * This function returns a printable string for a command type.
     302 ****************************************************************************************
     303 * type  :  command type
     304 ***************************************************************************************/
     305char * socket_cmd_type_str( uint32_t type );
     306
     307/****************************************************************************************
     308 * This function returns a printable string for a command status.
     309 ****************************************************************************************
     310 * sts   : command status.
     311 ***************************************************************************************/
     312char * socket_cmd_sts_str( uint32_t sts );
     313
     314
     315
     316/****************************************************************************************
     317 *      Functions used by the NIC_TX and NIC_RX server threads.
     318 ***************************************************************************************/
     319
     320/****************************************************************************************
     321 * This function is called by the dev_nic_rx_handle_tcp() function, executed by the
     322 * NIC_RX[channel] server thread, to register a R2T request defined by the <flags>
     323 * argument in the socket R2T queue, specified by the <queue_xp> argument.
     324 * This function unblocks the NIC_TX[channel] server thread, identified by the <channel>
     325 * argumentfrom the THREAD_BLOCKED_CLIENT condition.
     326 ****************************************************************************************
     327 * @ queue_xp   : [in] extended pointer on the R2T qeue descriptor.
     328 * @ flags      : [in] flags to be set in the TCP segment.
     329 * @ channel    : [in] NIC channel (both TX & RX).
     330 ***************************************************************************************/
     331void socket_put_r2t_request( xptr_t    queue_xp,
     332                             uint32_t  flags,
     333                             uint32_t  channel );
     334 
     335/****************************************************************************************
     336 * This function is called by the dev_nic_rx_handle_tcp() function to register
     337 * a client connection request, defined by the <remote_addr>, <remote_port>,
     338 * <remote_iss>, and <remote_window> arguments, * in the CRQ queue, specified
     339 * by the <queue_xp> argument.
     340 ****************************************************************************************
     341 * @ queue_xp      : [in] extended pointer on the CRQ qeue descriptor.
     342 * @ remote_addr   : [in] remote socket IP address.
     343 * @ remote_port   : [in] remote socket port.
     344 * @ remote_iss    : [in] remote socket initial sequence number.
     345 * @ remote_window : [in] remote socket receive window
     346 * @ return 0 if success / return -1 if queue full.
     347 ***************************************************************************************/
     348error_t socket_put_crq_request( xptr_t    queue_xp,
     349                                uint32_t  remote_addr,
     350                                uint32_t  remote_port,
     351                                uint32_t  remote_iss,
     352                                uint32_t  remote_window );
     353
     354/****************************************************************************************
     355 * This function is called by the socket_accept() function to extract a connection
     356 * request from a CRQ queue, specified by the <queue_xp> argument, to the buffers
     357 * defined by <remote_addr>, <remote_port>, <remote_iss>, and <remote_window>.
     358 *****************************************************************************************
     359 * @ queue_xp      : [in]  extended pointer on the CRQ qeue descriptor.
     360 * @ remote_addr   : [out] buffer for remote socket IP address.
     361 * @ remote_port   : [out] buffer for remote socket port.
     362 * @ remote_iss    : [out] buffer for remote socket initial sequence number.
     363 * @ remote_window : [out] buffer for remote socket receive window
     364 * @ return 0 if success / return -1 if queue empty.
     365 ***************************************************************************************/
     366error_t socket_get_crq_request( xptr_t     queue_xp,
     367                                uint32_t * remote_addr,
     368                                uint32_t * remote_port,
     369                                uint32_t * remote_iss,
     370                                uint32_t * remote_window );
     371
     372/****************************************************************************************
     373 * This blocking function diplays the socket state (including the TCB).
     374 ****************************************************************************************
     375 * @ socket_xp     : [in] extended pointer on socket descriptor.
     376 $ @ string        : [in] name of calling function.
     377 ***************************************************************************************/
     378void socket_display( xptr_t         socket_xp,
     379                     const char   * func_str );
     380
     381
     382
     383/****************************************************************************************
     384 *      Functions implementing the socket related system calls
     385 ***************************************************************************************/
     386
     387/****************************************************************************************
     388 * This function implements the socket() syscall.
     389 * This function allocates and intializes in the calling thread cluster:
     390 * - a new socket descriptor, defined by the <domain> and <type> arguments,
     391 * - a new file descriptor, associated to this socket,
     392 * It registers the file descriptor in the reference process fd_array[],
     393 * set the socket state to UNBOUND, and returns the <fdid> value.
     394 ****************************************************************************************
     395 * @ domain  : [in] socket protocol family (AF_UNIX / AF_INET)
     396 * @ type    : [in] socket type (SOCK_DGRAM / SOCK_STREAM).
     397 * @ return a file descriptor <fdid> if success / return -1 if failure.
     398 ***************************************************************************************/
     399int socket_build( uint32_t   domain,
     400                  uint32_t   type );
     401
     402/****************************************************************************************
     403 * This function implements the bind() syscall.
     404 * It assigns an IP address, defined by the <local_addr> argument, and a port number,
     405 * defined by the <local_port> argument to an unnamed local socket, identified by the
     406 * <fdid> argument, and set the socket state to BOUND. It applies to UDP or TCP sockets.
     407 * It does not require any service from the NIC_TX and NIC_RX server threads.
     408 * It can be called by a thread running in any cluster.
     409 ****************************************************************************************
     410 * @ fdid         : [in] file descriptor index identifying the socket.
     411 * @ local_addr   : [in] local IP address.
     412 * @ local_port   : [in] local port.
     413 * @ return 0 if success / return -1 if failure.
     414 ***************************************************************************************/
     415int socket_bind( uint32_t  fdid,
     416                 uint32_t  addr,
     417                 uint16_t  port );
     418
     419/****************************************************************************************
     420 * This function implements the listen() syscall().
     421 * It is called by a (local) server process to specify the max size of the CRQ queue
     422 * for a socket identified by the <fdid> argument, that expect connection requests
     423 * from one or several (remote) client processes.  The selected socket CRQ is supposed
     424 * to register all connections requests, whatever the client IP address and port values.
     425 * This function applies only to a TCP socket, that must be in the BOUND state.
     426 * The <fdid> socket is set to the LISTEN state.
     427 * It does not require any service from the NIC_TX and NIC_RX server threads.
     428 * It can be called by a thread running in any cluster.
     429 ****************************************************************************************
     430 * Implementation notes :
     431 * The number N of channels available in the NIC contrôler can be larger than 1.
     432 * Depending on the remote client IP address and port, the  connection request can be
     433 * received by any NIC_RX[k] server thread. To find the relevant listening socket, each
     434 * NIC_RX[k] server thread must be able to scan the set of all listening sockets.
     435 * Therefore a list of listening sockets is implemented as a dedicated xlist, rooted in
     436 * the NIC_RX[0] chdev extension, and using the listening socket <rx_list> field,
     437 * because a listening socket is never used to move data. 
     438 ****************************************************************************************
     439 * @ fdid      : [in] file descriptor index identifying the local server socket.
     440 * @ crq_depth : [in] depth of CRQ queue of pending connection requests.
     441 ***************************************************************************************/
     442int socket_listen( uint32_t fdid,
     443                   uint32_t crq_depth );
     444
     445/****************************************************************************************
     446 * This blocking function implements the accept() syscall().
     447 * It applies only to TCP sockets in the LISTEN state.
     448 * It is executed by a server process, waiting for one (or several) client process(es)
     449 * requesting a connection on a listening socket identified by the <fdid> argument.
     450 * This socket must have been previouly created with socket(), bound to a local address
     451 * with bind(), and listening for connections after a listen(). It  blocks on the <IO>
     452 * condition if the CRQ is empty. Otherwise, it get a pending connection request from
     453 * the listening socket CRQ queue, and creates & initializes a new socket with
     454 * the same properties as the listening socket, allocating a new file descriptor
     455 * for this new socket. It returns the new socket fdid as well as the remote IP address
     456 * and port, but only when the new socket is set to the ESTAB state. The new socket
     457 * cannot accept connections, but the listening socket keeps open for new connections. 
     458 ****************************************************************************************
     459 * Implementation Note:
     460 * This blocking function contains two blocking conditions because it requests services
     461 * to both the NIC_RX server thread, and he NIC_TX server thread.
     462 * It can be split in five steps:
     463 * 1) It makes several checkings on the listening socket domain, type, and state.
     464 * 2) If the socket CRQ queue is empty, the function makes an SOCKET_RX_ACCEPT command
     465 *    to the NIC_RX server thread, waiting registration of a connection request in the
     466 *    CRQ queue. Then it blocks on the <IO> condition and deschedules. It is unblocked
     467 *    by the NIC_RX server thread receiving a valid TCP SYN segment.
     468 * 3) When it found a pending request, it creates a new socket with the same properties
     469 *    as the listening socket, and a new file descriptor for this socket. It initializes
     470 *    the new socket descriptor using the values in the registered connect_request_t
     471 *    structure, and set this new socket to the SYN_RECV state.
     472 * 4) Then it makes a SOCKET_TX_command to the NIC_TX thread, requesting a TCP SYN_ACK
     473 *    segment to the remote socket. Then, it blocks on <IO> condition and dechedules.
     474 *    It is unblocked by the NIC_RX server thread when this SYN_ACK is acknowledged,
     475 *    and the new socket is set in ESTAB state (by the NIC_RX server).
     476 * 5) Finally, it returns the new socket fdid, and registers, in the <address> and
     477 *    <port> arguments, the remote client IP address & port.
     478 ****************************************************************************************
     479 * @ fdid         : [in] file descriptor index identifying the listening socket.
     480 * @ address      : [out] server IP address.
     481 * @ port         : [out] server port address length in bytes.
     482 * @ return the new socket <fdid> if success / return -1 if failure
     483 ***************************************************************************************/
     484int socket_accept( uint32_t   fdid,
     485                   uint32_t * address,
     486                   uint16_t * port );
     487
     488/****************************************************************************************
     489 * This blocking function implements the connect() syscall.
     490 * It is used by a client process to connect a local socket identified by
     491 * the <fdid> argument, to a remote socket identified by the <remote_addr> and
     492 * <remote_port> arguments. It can be used for both  UDP and TCP sockets.
     493 * It computes the nic_channel index [k] from <remote_addr> and <remote_port> values,
     494 * and initializes "remote_addr","remote_port", "nic_channel" in local socket.
     495 * It registers the socket in the lists of sockets rooted in the NIC_RX[k] & NIC_TX[k]
     496 * chdevs. It can be called by a thread running in any cluster.
     497 * It returns only when the local socket is in the ESTAB state, or to report an error.
     498 ****************************************************************************************
     499 * Implementation Note:
     500 * - For a TCP socket, it updates the "remote_addr", "remote_port", "nic_channel" fields
     501 *   in the socket descriptor defined by the <fdid> argument, and register this socket,
     502 *   in the lists of sockets attached to the NIC_TX[k] and NIC_RX[k] chdevs.
     503 *   Then, it builds a TX_CONNECT command to the NIC_TX server thread to send a SYN to
     504 *   the remote socket, unblocks the NIC_TX server thread from the <CLIENT> condition,
     505 *   blocks itself on <IO> condition and deschedules. It is unblocked by the NIC_RX
     506 *   server thread when this thread receive the expected SYN-ACK, and the local socket
     507 *   has been set to the ESTAB state, or when an error is reported in "tx_error" field.
     508 * - For an UDP socket, it simply updates "remote_addr", "remote_port", "nic_channel"
     509 *   in the socket descriptor defined by the <fdid> argument, and register this socket
     510 *   in the lists of sockets attached to the NIC_TX[k] and NIC_RX[k] chdevs.
     511 *   Then, it set the socket to the ESTAB state, or returns an error without blocking.
     512 ****************************************************************************************
     513 * @ fdid          : [in] file descriptor index identifying the socket.
     514 * @ remote_addr   : [in] remote IP address.
     515 * @ remote_port   : [in] remote port.
     516 * @ return 0 if success / return -1 if failure.
     517 ***************************************************************************************/
     518int socket_connect( uint32_t  fdid,
     519                    uint32_t  remote_addr,
     520                    uint16_t  remote_port );
     521
     522/****************************************************************************************
     523 * This blocking function implements the send() syscall.
     524 * It is used to send data stored in the user buffer, identified the <u_buf> and <length>
     525 * arguments, to a connected (TCP or UDP) socket, identified by the <fdid> argument.
     526 * The work is actually done by the NIC_TX server thread, and the synchronisation
     527 * between the client and the server threads uses the "rx_valid" set/reset flip-flop:
     528 * The client thread registers itself in the socket descriptor, registers in the queue
     529 * rooted in the NIC_TX[index] chdev, set "rx_valid", unblocks the server thread, and
     530 * finally blocks on THREAD_BLOCKED_IO, and deschedules.
     531 * When the TX server thread completes the command (all data has been sent for an UDP
     532 * socket, or acknowledged for a TCP socket), the server thread reset "rx_valid" and
     533 * unblocks the client thread.
     534 * This function can be called by a thread running in any cluster.
     535 * WARNING : This implementation does not support several concurent SEND/SENDTO commands
     536 * on the same socket, as only one TX thread can register in a given socket.
     537 ****************************************************************************************
     538 * @ fdid      : [in] file descriptor index identifying the socket.
     539 * @ u_buf     : [in] pointer on buffer containing packet in user space.
     540 * @ length    : [in] packet size in bytes.
     541 * @ return number of sent bytes if success / return -1 if failure.
     542 ***************************************************************************************/
     543int socket_send( uint32_t    fdid,
     544                 uint8_t   * u_buf,
     545                 uint32_t    length );
     546
     547/****************************************************************************************
     548 * This blocking function implements the sendto() syscall.
     549 * It registers the <remote_addr> and <remote_port> arguments in the local socket
     550 * descriptor, and does the same thing as the socket_send() function above,
     551 * but can be called  on an unconnected UDP socket.
     552 ****************************************************************************************
     553 * @ fdid        : [in] file descriptor index identifying the socket.
     554 * @ u_buf       : [in] pointer on buffer containing packet in user space.
     555 * @ length      : [in] packet size in bytes.
     556 * @ remote_addr : [in] destination IP address.
     557 * @ remote_port : [in] destination port.
     558 * @ return number of sent bytes if success / return -1 if failure.
     559 ***************************************************************************************/
     560int socket_sendto( uint32_t    fdid,
     561                   uint8_t   * u_buf,
     562                   uint32_t    length,
     563                   uint32_t    remote_addr,
     564                   uint32_t    remote_port );
     565
     566/****************************************************************************************
     567 * This blocking function implements the recv() syscall.
     568 * It is used to receive data that has been stored by the NIC_RX server thread in the
     569 * rx_buf of a connected (TCP or UDP) socket, identified by the <fdid> argument.
     570 * The synchronisation between the client and the server threads uses the "rx_valid"
     571 * set/reset flip-flop: If "rx_valid" is set, the client simply moves the available
     572 * data from the "rx_buf" to the user buffer identified by the <u_buf> and <length>
     573 * arguments, and reset the "rx_valid" flip_flop. If "rx_valid" is not set, the client
     574 * thread register itself in the socket descriptor, registers in the clients queue rooted
     575 * in the NIC_RX[index] chdev, and finally blocks on THREAD_BLOCKED_IO, and deschedules.
     576 * The client thread is re-activated by the RX server, that set the "rx_valid" flip-flop
     577 * as soon as data is available in the "rx_buf". The number of bytes actually transfered
     578 * can be less than the user buffer size.
     579 * This  function can be called by a thread running in any cluster.
     580 * WARNING : This implementation does not support several concurent RECV/RECVFROM
     581 * commands on the same socket, as only one RX thread can register in a given socket.
     582 ****************************************************************************************
     583 * @ fdid      : [in] file descriptor index identifying the socket.
     584 * @ u_buf     : [in] pointer on buffer in user space.
     585 * @ length    : [in] buffer size in bytes.
     586 * @ return number of received bytes if success / return -1 if failure.
     587 ***************************************************************************************/
     588int socket_recv( uint32_t    fdid,
     589                 uint8_t   * u_buf,
     590                 uint32_t    length );
     591
     592/****************************************************************************************
     593 * This blocking function implements the recvfrom() syscall.
     594 * It registers the <remote_addr> and <remote_port> arguments in the local socket
     595 * descriptor, and does the same thing as the socket_recv() function above,
     596 * but can be called on an unconnected UDP socket.
     597 ****************************************************************************************
     598 * @ fdid        : [in] file descriptor index identifying the socket.
     599 * @ u_buf       : [in] pointer on buffer containing packet in user space.
     600 * @ length      : [in] packet size in bytes.
     601 * @ remote_addr : [in] destination IP address.
     602 * @ remote_port : [in] destination port.
     603 * @ return number of received bytes if success / return -1 if failure.
     604 ***************************************************************************************/
     605int socket_recvfrom( uint32_t    fdid,
     606                     uint8_t   * u_buf,
     607                     uint32_t    length,
     608                     uint32_t    remote_addr,
     609                     uint32_t    remote_port );
     610
     611/****************************************************************************************
     612 * This blocking function implements the close() syscall for a socket.
     613 * - For a UDP socket, it simply calls the static socket_destroy() function to release
     614 *   all structures associated to the local socket, including the file descriptor.
     615 * - For a TCP socket, it makes a CLOSE command to NIC_TX, and blocks on the <IO>
     616 *   condition. The close TCP hanshake is done by the NIC_TX and NIC_RX threads.
     617 *   It is unblocked when the socket is in CLOSED state, or when an error is reported.
     618 *   Finally, it calls the static socket_destroy() function to release all structures
     619 *   associated to the local socket, including the file descriptor.
     620 ****************************************************************************************
     621 * @ file_xp     : [in] extended pointer on file descriptor.
     622 * @ fdid        : [in] file descriptor index identifying the socket.
     623 * @ return 0 if success / return -1 if failure.
     624 ***************************************************************************************/
     625int socket_close( xptr_t     file_xp,
     626                  uint32_t   fdid );
     627
     628
     629#endif  /* _KSOCKET_H_ */
     630
     631
     632
  • trunk/kernel/kern/printk.c

    r625 r662  
    589589{
    590590    uint32_t line;
    591     uint32_t byte = 0;
     591    uint32_t byte;
     592    uint32_t nlines;
     593
     594    nlines = size >> 4;
     595    if( size & 0xF ) nlines++;
    592596
    593597    // get pointers on TXT0 chdev
     
    605609    nolock_printk("\n***** %s *****\n", string );
    606610
    607     for ( line = 0 ; line < (size>>4) ; line++ )
     611    for ( line = 0 , byte = 0 ; line < nlines ; line++ )
    608612    {
    609          nolock_printk(" %X | %b %b %b %b | %b %b %b %b | %b %b %b %b | %b %b %b %b \n",
    610          byte,
     613         nolock_printk(" %X | %b %b %b %b | %b %b %b %b | %b %b %b %b | %b %b %b %b |\n",
     614         buffer + byte,
    611615         buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3],
    612616         buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7],
  • trunk/kernel/kern/process.c

    r657 r662  
    10771077
    10781078///////////////////////////////////////////
     1079char * process_fd_type_str( uint32_t type )
     1080{
     1081    switch( type )
     1082    {
     1083        case INODE_TYPE_FILE : return "FILE";
     1084        case INODE_TYPE_DIR  : return "DIR";
     1085        case INODE_TYPE_FIFO : return "FIFO";
     1086        case INODE_TYPE_PIPE : return "PIPE";
     1087        case INODE_TYPE_SOCK : return "SOCK";
     1088        case INODE_TYPE_DEV  : return "DEV";
     1089        case INODE_TYPE_BLK  : return "BLK";
     1090        case INODE_TYPE_SYML : return "SYML";
     1091       
     1092        default              : return "undefined";
     1093    }
     1094}
     1095   
     1096///////////////////////////////////////////
    10791097void process_fd_init( process_t * process )
    10801098{
     
    10851103
    10861104    // initialize number of open files
    1087     process->fd_array.current = 0;
     1105    process->fd_array.max = 0;
    10881106
    10891107    // initialize array
     
    11011119    bool_t    found;
    11021120    uint32_t  id;
    1103     xptr_t    xp;
     1121    uint32_t  max;             // current value of max non-free slot index
     1122    xptr_t    entry_xp;        // current value of one fd_array entry
     1123    xptr_t    lock_xp;         // extended pointer on lock protecting fd_array
     1124    xptr_t    max_xp;          // extended pointer on max field in fd_array
    11041125
    11051126    // get target process cluster and local pointer
     
    11071128    cxy_t       process_cxy = GET_CXY( process_xp );
    11081129
    1109 // check target process is reference process
    1110 assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp ) ) ),
    1111 "client process must be reference process\n" );
     1130// check target process is owner process
     1131assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ),
     1132"process must be owner process\n" );
    11121133
    11131134#if DEBUG_PROCESS_FD_REGISTER
     
    11201141#endif
    11211142
    1122     // build extended pointer on lock protecting reference fd_array
    1123     xptr_t lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
     1143    // build extended pointers on lock & max
     1144    lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
     1145    max_xp  = XPTR( process_cxy , &process_ptr->fd_array.max );
    11241146
    11251147    // take lock protecting reference fd_array
     
    11281150    found   = false;
    11291151
     1152    // get current value of max_fdid
     1153    max = hal_remote_l32( max_xp );
     1154
    11301155    for ( id = 0; id < CONFIG_PROCESS_FILE_MAX_NR ; id++ )
    11311156    {
    1132         xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
    1133         if ( xp == XPTR_NULL )
     1157        // get fd_array entry
     1158        entry_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
     1159       
     1160        if ( entry_xp == XPTR_NULL )
    11341161        {
    1135             // update reference fd_array
     1162            // update fd_array
    11361163            hal_remote_s64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) , file_xp );
    1137                 hal_remote_atomic_add( XPTR( process_cxy , &process_ptr->fd_array.current ) , 1 );
    1138 
    1139             // exit
     1164
     1165            // update max when required
     1166            if( id > max ) hal_remote_s32( max_xp , id );
     1167
     1168            // increase file refcount
     1169            vfs_file_count_up( file_xp );
     1170
     1171            // exit loop
    11401172                        *fdid = id;
    11411173            found = true;
     
    11651197    pid_t       pid;           // target process PID
    11661198    lpid_t      lpid;          // target process LPID
     1199    xptr_t      file_xp;       // extended pointer on file descriptor
    11671200    xptr_t      iter_xp;       // iterator for list of process copies
    11681201    xptr_t      copy_xp;       // extended pointer on process copy
     
    11701203    cxy_t       copy_cxy;      // process copy cluster identifier
    11711204
    1172 // check process_xp argument
    1173 assert( (process_xp != XPTR_NULL), "process_xp argument cannot be XPTR_NULL");
    1174 
    11751205    // get target process cluster and local pointer
    11761206    process_t * process_ptr = GET_PTR( process_xp );
    11771207    cxy_t       process_cxy = GET_CXY( process_xp );
    11781208
     1209// check target process is owner process
     1210assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ),
     1211"process must be owner process\n" );
     1212
    11791213    // get target process pid and lpid
    11801214    pid  = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
    11811215    lpid = LPID_FROM_PID( pid );
    1182 
    1183     // get process descriptor in owner cluster and in reference cluster
    1184     xptr_t  owner_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ));
    1185     xptr_t  ref_xp   = hal_remote_l64( XPTR( process_cxy , &process_ptr->ref_xp   ));
    1186 
    1187 // check target process in in owner cluster
    1188 assert( (process_xp == owner_xp), "target process must be in owner process\n" );
    11891216
    11901217#if DEBUG_PROCESS_FD_REMOVE
     
    11961223#endif
    11971224
     1225    // get extended pointer on file descriptor
     1226    file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[fdid] ));
     1227
    11981228    // build extended pointers on list_of_copies root and lock (in owner cluster)
    11991229    xptr_t copies_root_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_root[lpid] );
    12001230    xptr_t copies_lock_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_lock[lpid] );
    12011231 
    1202     // get reference process cluster and local pointer
    1203     process_t * ref_ptr = GET_PTR( ref_xp );
    1204     cxy_t       ref_cxy = GET_CXY( ref_xp );
    1205 
    1206     // build extended pointer on lock protecting reference fd_array
    1207     xptr_t fd_lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
    1208 
    1209     // take lock protecting reference fd_array
     1232    // build extended pointer on fd_array lock and max
     1233    xptr_t fd_lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
     1234    xptr_t fd_max_xp  = XPTR( process_cxy , &process_ptr->fd_array.max );
     1235
     1236    // take lock protecting fd_array
    12101237        remote_queuelock_acquire( fd_lock_xp );
    12111238
    12121239    // take the lock protecting the list of copies
    12131240    remote_queuelock_acquire( copies_lock_xp );
     1241
     1242    // get max value
     1243    uint32_t max = hal_remote_l32( fd_max_xp );
    12141244
    12151245    // loop on list of process copies
     
    12231253        // release the fd_array entry in process copy
    12241254        hal_remote_s64( XPTR( copy_cxy , &copy_ptr->fd_array.array[fdid] ), XPTR_NULL );
    1225     }
     1255
     1256        // decrease file refcount
     1257        vfs_file_count_down( file_xp );
     1258    }
     1259
     1260    // update max when required
     1261    if( fdid == max ) hal_remote_s32( fd_max_xp , max-1 );
    12261262
    12271263    // release the lock protecting reference fd_array
     
    12401276}  // end process_fd_remove()
    12411277
    1242 ////////////////////////////////////////////////
    1243 xptr_t process_fd_get_xptr( process_t * process,
    1244                             uint32_t    fdid )
     1278//////////////////////////////////////////////
     1279void process_fd_clean_all( xptr_t process_xp )
     1280{
     1281    uint32_t  id;
     1282    xptr_t    file_xp;         // one fd_array entry
     1283    xptr_t    lock_xp;         // extendad pointer on lock protecting fd_array
     1284    uint32_t  max;             // number of registered files
     1285    error_t   error;
     1286
     1287    // get process cluster, local pointer and PID
     1288    process_t * process_ptr = GET_PTR( process_xp );
     1289    cxy_t       process_cxy = GET_CXY( process_xp );
     1290    pid_t       pid         = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) );
     1291
     1292// check target process is owner process
     1293assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp )) ),
     1294"process must be owner process\n" );
     1295
     1296#if DEBUG_PROCESS_FD_CLEAN_ALL
     1297thread_t * this  = CURRENT_THREAD;
     1298uint32_t   cycle = (uint32_t)hal_get_cycles();
     1299if( DEBUG_PROCESS_FD_CLEAN_ALL < cycle )
     1300printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n",
     1301__FUNCTION__, this->process->pid, this->trdid, pid, cycle );
     1302
     1303process_fd_display( process_xp );
     1304#endif
     1305
     1306    // build extended pointer on lock protecting the fd_array
     1307    lock_xp = XPTR( process_cxy , &process_ptr->fd_array.lock );
     1308
     1309    // get max index for fd_array
     1310    max = hal_remote_l32( XPTR( process_cxy , &process_ptr->fd_array.max ));
     1311
     1312    // take lock protecting fd_array
     1313        remote_queuelock_acquire( lock_xp );
     1314
     1315    for ( id = 0; id <= max ; id++ )
     1316    {
     1317        // get fd_array entry
     1318        file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[id] ) );
     1319       
     1320        if ( file_xp != XPTR_NULL )
     1321        {
     1322            // close the file or socket
     1323            error = sys_close( id );
     1324
     1325            if( error )
     1326            printk("/n[ERROR] in %s : cannot close the file %d for process %x\n",
     1327            __FUNCTION__, id, pid );
     1328        }
     1329    }
     1330
     1331    // release lock protecting fd_array
     1332        remote_queuelock_release( lock_xp );
     1333
     1334#if DEBUG_PROCESS_FD_CLEAN_ALL
     1335cycle = (uint32_t)hal_get_cycles();
     1336if( DEBUG_PROCESS_FD_CLEAN_ALL < cycle )
     1337printk("\n[%s] thread[%x,%x] exit for process %x / cycle %d\n",
     1338__FUNCTION__, this->process->pid, this->trdid, pid, cycle );
     1339#endif
     1340
     1341}  // end process_fd_clean_all()
     1342
     1343//////////////////////////////////////////////////////////////
     1344xptr_t process_fd_get_xptr_from_owner( xptr_t      process_xp,
     1345                                       uint32_t    fdid )
     1346{
     1347    cxy_t       process_cxy = GET_CXY( process_xp );
     1348    process_t * process_ptr = GET_PTR( process_xp );
     1349
     1350assert( (hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp )) == process_xp),
     1351"process_xp argument must be the owner process" );
     1352
     1353    // access owner process fd_array
     1354    return hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[fdid] ));
     1355
     1356}  // end process_fd_get_xptr_from_owner()
     1357
     1358///////////////////////////////////////////////////////////
     1359xptr_t process_fd_get_xptr_from_local( process_t * process,
     1360                                       uint32_t    fdid )
    12451361{
    12461362    xptr_t  file_xp;
     
    12521368    if( file_xp == XPTR_NULL )
    12531369    {
    1254         // get reference process cluster and local pointer
    1255         xptr_t      ref_xp  = process->ref_xp;
    1256         cxy_t       ref_cxy = GET_CXY( ref_xp );
    1257         process_t * ref_ptr = GET_PTR( ref_xp );
    1258 
    1259         // build extended pointer on lock protecting reference fd_array
    1260         lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );
    1261 
    1262         // take lock protecting reference fd_array
     1370        // get owner process cluster and local pointer
     1371        xptr_t      owner_xp  = process->owner_xp;
     1372        cxy_t       owner_cxy = GET_CXY( owner_xp );
     1373        process_t * owner_ptr = GET_PTR( owner_xp );
     1374
     1375        // build extended pointer on lock protecting fd_array
     1376        lock_xp = XPTR( owner_cxy , &owner_ptr->fd_array.lock );
     1377
     1378        // take lock protecting fd_array
    12631379            remote_queuelock_acquire( lock_xp );
    12641380
    12651381        // access reference process descriptor
    1266         file_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->fd_array.array[fdid] ) );
    1267 
    1268         // update local fd_array if found
    1269         if( file_xp != XPTR_NULL )  process->fd_array.array[fdid] = file_xp;
     1382        file_xp = hal_remote_l64( XPTR( owner_cxy , &owner_ptr->fd_array.array[fdid] ) );
     1383
     1384        if( file_xp != XPTR_NULL ) 
     1385        {
     1386           // update local fd_array
     1387            process->fd_array.array[fdid] = file_xp;
    12701388       
    1271         // release lock protecting reference fd_array
     1389            // increase file refcount
     1390            vfs_file_count_up( file_xp );
     1391        }
     1392
     1393        // release lock protecting fd_array
    12721394            remote_queuelock_release( lock_xp );
    12731395    }
     
    12751397    return file_xp;
    12761398
    1277 }  // end process_fd_get_xptr()
     1399}  // end process_fd_get_xptr_from_local()
    12781400
    12791401///////////////////////////////////////////
     
    13191441bool_t process_fd_array_full( void )
    13201442{
    1321     // get extended pointer on reference process
    1322     xptr_t ref_xp = CURRENT_THREAD->process->ref_xp;
    1323 
    1324     // get reference process cluster and local pointer
    1325     process_t * ref_ptr = GET_PTR( ref_xp );
    1326     cxy_t       ref_cxy = GET_CXY( ref_xp );
    1327 
    1328     // get number of open file descriptors from reference fd_array
    1329     uint32_t current = hal_remote_l32( XPTR( ref_cxy , &ref_ptr->fd_array.current ) );
    1330 
    1331         return ( current >= CONFIG_PROCESS_FILE_MAX_NR );
     1443    // get extended pointer on owner process
     1444    xptr_t owner_xp = CURRENT_THREAD->process->owner_xp;
     1445
     1446    // get owner process cluster and local pointer
     1447    process_t * owner_ptr = GET_PTR( owner_xp );
     1448    cxy_t       owner_cxy = GET_CXY( owner_xp );
     1449
     1450    // get number of open file descriptors from fd_array
     1451    uint32_t max = hal_remote_l32( XPTR( owner_cxy , &owner_ptr->fd_array.max ));
     1452
     1453        return ( max == CONFIG_PROCESS_FILE_MAX_NR - 1 );
    13321454}
    13331455
     1456////////////////////////////////////////////
     1457void process_fd_display( xptr_t process_xp )
     1458{
     1459    uint32_t      fdid;
     1460    xptr_t        file_xp;
     1461    vfs_file_t *  file_ptr;
     1462    cxy_t         file_cxy;
     1463    uint32_t      file_type;
     1464    xptr_t        inode_xp;
     1465    vfs_inode_t * inode_ptr;
     1466
     1467    char          name[CONFIG_VFS_MAX_NAME_LENGTH];
     1468
     1469    // get process cluster and local pointer
     1470    process_t * process_ptr = GET_PTR( process_xp );
     1471    cxy_t       process_cxy = GET_CXY( process_xp );
     1472
     1473    // get process PID
     1474    pid_t  pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid ));
     1475
     1476    // get pointers on owner process descriptor
     1477    xptr_t      owner_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ));
     1478    process_t * owner_ptr = GET_PTR( owner_xp );
     1479    cxy_t       owner_cxy = GET_CXY( owner_xp );
     1480
     1481    // get max fdid from owner process descriptor
     1482    uint32_t max = hal_remote_l32( XPTR( owner_cxy , &owner_ptr->fd_array.max ));
     1483
     1484    printk("\n***** fd_array for pid %x in cluster %x / max %d *****\n",
     1485    pid, process_cxy, max );
     1486
     1487    for( fdid = 0 ; fdid <= max ; fdid++ )
     1488    {
     1489        // get pointers on file descriptor
     1490        file_xp  = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[fdid] ));
     1491        file_ptr = GET_PTR( file_xp );
     1492        file_cxy = GET_CXY( file_xp );
     1493
     1494        if( file_xp != XPTR_NULL )
     1495        {
     1496            // get file type
     1497            file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ));
     1498
     1499            // get file name for a true file
     1500            if( file_type == INODE_TYPE_FILE )
     1501            {
     1502                // get inode pointers
     1503                inode_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ));
     1504                inode_xp  = XPTR( file_cxy , inode_ptr );
     1505
     1506                // get file name
     1507                vfs_inode_get_name( inode_xp , name );
     1508
     1509                // display relevant file decriptor info
     1510                printk(" - %d : type %s (%s)\n",
     1511                fdid , process_fd_type_str(file_type), name );
     1512            }
     1513            else
     1514            {
     1515                // display relevant file decriptor info
     1516                printk(" - %d : type %s\n",
     1517                fdid , process_fd_type_str(file_type) );
     1518            }
     1519        }
     1520        else
     1521        {
     1522            // display relevant file decriptor info
     1523            printk(" - %d : empty slot\n",
     1524            fdid );
     1525        }
     1526    }
     1527}   // end process_fd_display()
    13341528
    13351529////////////////////////////////////////////////////////////////////////////////////
  • trunk/kernel/kern/process.h

    r657 r662  
    7070/*********************************************************************************************
    7171 * This structure defines an array of extended pointers on the open file descriptors
    72  * for a given process. We use an extended pointer because the open file descriptors
    73  * are always stored in the same cluster as the inode associated to the file.
    74  * A free entry in this array contains the XPTR_NULL value.
     72 * for a given process. The file descriptors are always stored in the same cluster
     73 * as the inode associated to the file. A free entry in this array contains XPTR_NULL.
    7574 * The array size is defined by the CONFIG_PROCESS_FILE_MAX_NR parameter.
    7675 *
    77  * NOTE: - Only the fd_array[] in the reference process contains a complete list of open
     76 * NOTE: - Only the fd_array[] in the reference process contains the complete list of open
    7877 *         files, and is protected by the lock against concurrent access.
    79  *       - the fd_array[] in a process copy is simply a cache containing a subset of the
    80  *         open files to speed the fdid to xptr translation, but the "lock" and "current
     78 *       - the fd_array[] in a process copy is not used.
     79 *         open files to speed the fdid to xptr translation, but the "lock" and "max"
    8180 *         fields are not significant for these copies.
    82  *       - the modifications made by the process_fd_remove() function are done in the
    83  *         reference cluster in all process_copies.
    84  *       - The modifications made by the process_fd_register() function are done in the
    85  *         reference cluster, and in the cluster containing the calling thread.
     81 *       - The modifications made by the process_fd_register() function are only done
     82 *         in the owner cluster.
     83 *       - The modifications made by the process_fd_remove() function are done in the
     84 *         owner cluster, and in all process_copies.
     85 *       - In case of miss on the local fd_array, the process_fd_get_xptr() access the
     86 *         owner cluster fd_array, and update the fd_array local copy.
    8687 ********************************************************************************************/
    8788
     
    8990{
    9091        remote_queuelock_t lock;                              /*! lock protecting fd_array      */
    91     uint32_t           current;                           /*! current number of open files  */
     92    uint32_t           max;                               /*! max non-free slot index       */
    9293        xptr_t             array[CONFIG_PROCESS_FILE_MAX_NR]; /*! open file descriptors         */
    9394}
     
    278279/*********************************************************************************************
    279280 * This function releases all memory allocated for a process descriptor in the local cluster,
    280  * including memory allocated for embedded substructures (fd_array, vmm, etc).
     281 * including memory allocated for embedded sub-structures (fd_array, vmm, etc).
    281282 * The local th_tbl[] array must be empty.
    282283 *********************************************************************************************
     
    428429
    429430
    430 /********************   File Management Operations   ****************************************/
     431/********************     fd_array  operations       ****************************************/
     432
     433
     434/*********************************************************************************************
     435 * This function returns a printable string for a file descriptor type.
     436 * These file types are defined in the <vfs.h> file.
     437 *********************************************************************************************
     438 * @ type     : [in] file type.
     439 ********************************************************************************************/
     440char * process_fd_type_str( uint32_t type );
    431441
    432442/*********************************************************************************************
    433443 * This function initializes all entries of the local fd_array as empty.
    434444 *********************************************************************************************
    435  * @ process  : pointer on the local process descriptor.
     445 * @ process  : [in] pointer on the local process descriptor.
    436446 ********************************************************************************************/
    437447void process_fd_init( process_t * process );
    438448
    439449/*********************************************************************************************
    440  * This function allocates a free slot in the fd_array of the reference process descriptor
    441  * identified by the <process_xp> argument, register the <file_xp> argument in the
    442  * allocated slot, and return the slot index in the <fdid> buffer.
    443  * Note: we must use the reference process descriptor, because the reference fd_array is
    444  * contained in the reference cluster.  It can be called by any thread in any cluster.
    445  * It takes the lock protecting the reference fd_array against concurrent accesses.
     450 * This function allocates a free slot in the owner cluster process fd_array identified
     451 * by the <process_xp> argument, register the <file_xp> argument in the allocated slot,
     452 * and return the slot index in the <fdid> buffer.
     453 * It can be called by any thread in any cluster.
     454 * It takes the lock protecting the fd_array against concurrent accesses.
     455 * Note: we must use the owner process descriptor, because this fd_array must
     456 * contain all files open by a given process.
    446457 *********************************************************************************************
    447458 * @ process_xp : [in]  extended pointer on client reference process.
    448459 * @ file_xp    : [in]  extended pointer on the file descriptor to be registered.
    449  * @ fdid       : [out] buffer for fd_array slot index.
    450  * @ return 0 if success / return EMFILE if array full.
     460 * @ fdid       : [out] buffer for allocated fd_array slot index.
     461 * @ return 0 if success / return -1 if array full.
    451462 ********************************************************************************************/
    452463error_t process_fd_register( xptr_t      process_xp,
     
    455466
    456467/*********************************************************************************************
    457  * This function uses as many remote accesses as required, to reset an entry in fd_array[],
     468 * This function uses as many remote accesses as required, to reset one fd_array[] entry,
    458469 * identified by the <fdid> argument, in all clusters containing a copy of the
    459470 * process descriptor, identified by the <process_xp> argument.
     471 * It can be called by any thread in any cluster.
     472 * It takes the lock protecting the fd_array against concurrent accesses.
    460473 * Note: we must use the owner process descriptor, because only this owner cluster contains
    461  * the list of process copies. It can be called by any thread in any cluster.
    462  * It takes the lock protecting the reference fd_array against concurrent accesses.
    463  *********************************************************************************************
    464  * @ process  : [in] pointer on the local process descriptor.
    465  * @ fdid     : [in] file descriptor index in the fd_array.
     474 * the complete list of process copies.
     475 *********************************************************************************************
     476 * @ process_xp  : [in] extended pointer on the owner process descriptor.
     477 * @ fdid        : [in] file descriptor index in the fd_array.
    466478 ********************************************************************************************/
    467479void process_fd_remove( xptr_t     process_xp,
     
    469481
    470482/*********************************************************************************************
    471  * This function returns an extended pointer on a file descriptor identified by its index
    472  * in fd_array. It can be called by any thread running in any cluster.
     483 * This function scan the fd_array to close all files (or sockets) registered in the process
     484 * fd_array identified by the <process_xp> argument. It call the sys_close() function for
     485 * each registered entry, to release all allocated memory, and reset this entry in all
     486 * process descriptors copies.
     487 * It takes the lock protecting the fd_array against concurrent accesses.
     488 * Note: we must use the owner process descriptor, because only this owner cluster contains
     489 * the complete list of process copies.
     490 *********************************************************************************************
     491 * @ process_xp  : [in] extended pointer on the owner process descriptor.
     492 ********************************************************************************************/
     493void process_fd_clean_all( xptr_t process_xp );
     494
     495/*********************************************************************************************
     496 * This function returns an extended pointer on a file descriptor identified by its <fdid>
     497 * index in fd_array of the local process, identified by the <process> argument.
     498 * It can be called by any thread running in any cluster.
    473499 * It accesses first the local process descriptor. In case of local miss, it takes
    474500 * the lock protecting the reference fd_array, and access the reference process descriptor.
    475  * It updates the local fd_array when the file descriptor exists in reference cluster.
    476  * It takes the lock protecting the reference fd_array against concurrent accesses.
    477  * The file descriptor refcount is not incremented.
    478  *********************************************************************************************
    479  * @ process  : pointer on the local process descriptor.
     501 * It updates the local fd_array when the file descriptor exists in owner cluster.
     502 * It release the lock protecting the reference fd_array.
     503 *********************************************************************************************
     504 * @ process  : local pointer on local process descriptor.
    480505 * @ fdid     : file descriptor index in the fd_array.
    481506 * @ return extended pointer on file descriptor if success / return XPTR_NULL if not found.
    482507 ********************************************************************************************/
    483 xptr_t process_fd_get_xptr( process_t * process,
    484                             uint32_t    fdid );
     508xptr_t process_fd_get_xptr_from_local( process_t * process,
     509                                       uint32_t    fdid );
     510
     511/*********************************************************************************************
     512 * This function returns an extended pointer on a file descriptor identified by its <fdid>
     513 * index in the fd_array of the owner process, identified by the <process_xp> argument,
     514 * accessing directly the fd_array in owner cluster. It can be called by any thread running
     515 * in any cluster, but the local fd_array copy is not updated.
     516 *********************************************************************************************
     517 * @ process_xp  : extended pointer on the owner process descriptor.
     518 * @ fdid        : file descriptor index in the fd_array.
     519 * @ return extended pointer on file descriptor if success / return XPTR_NULL if not found.
     520 ********************************************************************************************/
     521xptr_t process_fd_get_xptr_from_owner( xptr_t      process_xp,
     522                                       uint32_t    fdid );
    485523
    486524/*********************************************************************************************
     
    508546bool_t process_fd_array_full( void );
    509547
    510 
     548/*********************************************************************************************
     549 * This debug function diplays on the kernel terminal TXT0 detailed informations on the
     550 * set of file descriptors registered in the fd_array of a process descriptor identified
     551 * by the <process_xp> argument.
     552 *********************************************************************************************
     553 * @ process_xp    : [in] extended pointer on process descriptor.
     554 ********************************************************************************************/
     555void process_fd_display( xptr_t process_xp );
    511556
    512557/********************   Thread Related Operations   *****************************************/
  • trunk/kernel/kern/scheduler.h

    r640 r662  
    22 * scheduler.h - Core scheduler definition.
    33 *
    4  * Author    Alain Greiner (2016,2017,2018)
     4 * Author    Alain Greiner (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
  • trunk/kernel/kern/thread.c

    r651 r662  
    33 *
    44 * Author  Ghassan Almaless (2008,2009,2010,2011,2012)
    5  *         Alain Greiner (2016,2017,2018,2019)
     5 *         Alain Greiner (2016,2017,2018,2019,2020)
    66 *
    77 * Copyright (c) UPMC Sorbonne Universites
     
    831831    hal_cpu_context_init( thread );
    832832
    833     // set THREAD_BLOCKED_IDLE for DEV threads
    834     if( type == THREAD_DEV ) thread->blocked |= THREAD_BLOCKED_IDLE;
    835 
    836833#if DEBUG_THREAD_KERNEL_CREATE
    837834cycle = (uint32_t)hal_get_cycles();
  • trunk/kernel/kern/thread.h

    r657 r662  
    8787#define THREAD_BLOCKED_JOIN      0x0010  /*! USR : blocked in exit / wait join        */
    8888#define THREAD_BLOCKED_SEM       0x0020  /*! USR : wait semaphore                     */
    89 #define THREAD_BLOCKED_PAGE      0x0040  /*! ??? : wait page access                  */
    90 #define THREAD_BLOCKED_IDLE      0x0080  /*! RPC : RPC_FIFO non empty                 */
     89#define THREAD_BLOCKED_PAGE      0x0040  /*! ??? : wait page access                   */
     90#define THREAD_BLOCKED_IDLE      0x0080  /*! RPC : wait RPC_FIFO non empty            */
    9191#define THREAD_BLOCKED_USERSYNC  0x0100  /*! USR : wait cond / mutex / barrier        */
    92 #define THREAD_BLOCKED_RPC       0x0200  /*! ANY : RPC completion                     */
     92#define THREAD_BLOCKED_RPC       0x0200  /*! ANY : wait RPC completion                */
    9393#define THREAD_BLOCKED_ISR       0x0400  /*! DEV : wait hardware IRQ                  */
    9494#define THREAD_BLOCKED_WAIT      0x0800  /*! USR : wait child process termination     */
    9595#define THREAD_BLOCKED_LOCK      0x1000  /*! ANY : wait queuelock or rwlock           */
    96 #define THREAD_BLOCKED_CLIENT    0x2000  /*! DEV : client threads queue non empty     */
     96#define THREAD_BLOCKED_CLIENT    0x2000  /*! DEV : wait clients queue non empty       */
    9797
    9898/***************************************************************************************
     
    195195        uint32_t            busylocks;       /*! number of taken busylocks                */
    196196
    197 #if DEBUG_BUSYLOCK
     197#if DEBUG_BUSYLOCK_TYPE
    198198    xlist_entry_t       busylocks_root;  /*! root of xlist of taken busylocks         */
    199199#endif
Note: See TracChangeset for help on using the changeset viewer.