Changeset 662 for trunk/kernel/kern
- Timestamp:
- Oct 10, 2020, 4:50:41 PM (4 years ago)
- Location:
- trunk/kernel/kern
- Files:
-
- 9 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/kern/chdev.c
r657 r662 301 301 server = CURRENT_THREAD; 302 302 303 #if( DEBUG_CHDEV_SERVER_RX || DEBUG_CHDEV_SERVER_TX ) 304 uint32_t rx_cycle = (uint32_t)hal_get_cycles(); 305 if( (chdev->is_rx) && (DEBUG_CHDEV_SERVER_RX < rx_cycle) ) 306 printk("\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 311 uint32_t tx_cycle = (uint32_t)hal_get_cycles(); 312 if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) ) 313 printk("\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 303 317 // build extended pointer on root & lock of client threads queue 304 318 root_xp = XPTR( local_cxy , &chdev->wait_root ); … … 309 323 while( 1 ) 310 324 { 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 #endif318 319 #if DEBUG_CHDEV_SERVER_TX320 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 #endif325 326 325 // check server thread can yield 327 326 thread_assert_can_yield( server , __FUNCTION__ ); … … 331 330 332 331 // check waiting queue state 333 if( xlist_is_empty( root_xp ) ) // waiting queue empty332 if( xlist_is_empty( root_xp ) ) // waiting queue empty 334 333 { 335 334 // release lock protecting the waiting queue … … 339 338 rx_cycle = (uint32_t)hal_get_cycles(); 340 339 if( (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",340 printk("\n[%s] RX server thread[%x,%x] blocks & deschedules / cycle %d\n", 342 341 __FUNCTION__ , server->process->pid, server->trdid, rx_cycle ); 343 342 #endif … … 346 345 tx_cycle = (uint32_t)hal_get_cycles(); 347 346 if( (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",347 printk("\n[%s] TX server thread[%x,%x] blocks & deschedules / cycle %d\n", 349 348 __FUNCTION__ , server->process->pid, server->trdid, tx_cycle ); 350 349 #endif 351 // block 350 // block and deschedule 352 351 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 355 rx_cycle = (uint32_t)hal_get_cycles(); 356 if( (chdev->is_rx) && (DEBUG_CHDEV_SERVER_RX < rx_cycle) ) 357 printk("\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 362 tx_cycle = (uint32_t)hal_get_cycles(); 363 if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) ) 364 printk("\n[%s] TX server thread[%x,%x] resumes / cycle %d\n", 365 __FUNCTION__ , server->process->pid, server->trdid, tx_cycle ); 366 #endif 367 356 368 } 357 else // waiting queue not empty369 else // waiting queue not empty 358 370 { 359 371 // get pointers on first client thread … … 414 426 if( (chdev->is_rx == 0) && (DEBUG_CHDEV_SERVER_TX < tx_cycle) ) 415 427 printk("\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, t X_cycle );428 __FUNCTION__, server->process->pid, server->trdid, client_pid, client_trdid, tx_cycle ); 417 429 #endif 418 430 -
trunk/kernel/kern/chdev.h
r657 r662 110 110 111 111 /****************************************************************************************** 112 * This structure defines a chdev descriptor.112 * This structure defines a chdev (channel device) descriptor. 113 113 * 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 * 116 117 * For each device type ***, the specific extension is defined in the "dev_***.h" file. 117 118 * 118 119 * NOTE . For most chdevs, the busylock is used to protect the waiting queue changes, 119 * when a thread registerin this queue, or is removed after service.120 * when a client registers in this queue, or is removed after service. 120 121 * . This busylock is also used to protect direct access to the shared 121 122 * 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 a123 * 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. 124 125 *****************************************************************************************/ 125 126 … … 142 143 uint32_t irq_id; /*! associated IRQ index in local ICU */ 143 144 144 xlist_entry_t wait_root; /*! root of client threads waiting queue*/145 xlist_entry_t wait_root; /*! root of clients waiting queue */ 145 146 remote_busylock_t wait_lock; /*! lock protecting waiting queue */ 147 uint32_t wait_nr; /*! number of registered clients (NIC only) */ 146 148 147 149 union -
trunk/kernel/kern/kernel_init.c
r657 r662 40 40 #include <thread.h> 41 41 #include <scheduler.h> 42 #include <ksocket.h> 42 43 #include <kmem.h> 43 44 #include <cluster.h> … … 130 131 char * lock_type_str[] = 131 132 { 132 "unused_0", // 0 133 "unused_0", // 0 must be unused to help debug 133 134 134 135 "CLUSTER_KCM", // 1 … … 153 154 "PROCESS_CWD", // 19 154 155 "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 175 178 }; 176 179 177 // debug variables to analyse the sys_read() and sys_write()syscalls timing180 // debug variables to analyse the sys_read() syscalls timing 178 181 179 182 #if DEBUG_SYS_READ … … 200 203 #endif 201 204 202 // these debug variables are usedto analyse the sys_write() syscall timing205 // debug variables to analyse the sys_write() syscall timing 203 206 204 207 #if DEBUG_SYS_WRITE … … 1488 1491 " - core descriptor : %d bytes\n" 1489 1492 " - scheduler : %d bytes\n" 1493 " - socket : %d bytes\n" 1490 1494 " - rpc fifo : %d bytes\n" 1491 1495 " - page descriptor : %d bytes\n" … … 1515 1519 sizeof( core_t ), 1516 1520 sizeof( scheduler_t ), 1521 sizeof( socket_t ), 1517 1522 sizeof( remote_fifo_t ), 1518 1523 sizeof( page_t ), -
trunk/kernel/kern/ksocket.c
r657 r662 1 1 /* 2 * socket.h - socket descriptor and API definition.3 * 4 * Authors Alain Greiner 2 * ksocket.c - kernel socket API implementation. 3 * 4 * Authors Alain Greiner (2016,2017,2018,2019,2020) 5 5 * 6 6 * Copyright (c) UPMC Sorbonne Universites 7 7 * 8 * This file is part of ALMOS-MKH 8 * This file is part of ALMOS-MKH. 9 9 * 10 10 * ALMOS-MKH is free software; you can redistribute it and/or modify it … … 18 18 * 19 19 * You should have received a copy of the GNU General Public License 20 * along with ALMOS-MKH ; if not, write to the Free Software Foundation,20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation, 21 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 22 */ 23 23 24 #ifndef _SOCKET_H_25 #define _SOCKET_H_26 27 24 #include <kernel_config.h> 28 25 #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> 30 30 #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 43 extern chdev_directory_t chdev_dir; // allocated in kernel_init.c 44 45 /////////////////////////////////////////// 46 char * 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 } 43 55 } 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 /////////////////////////////////////// 58 char * 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 } 100 67 } 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 ///////////////////////////////////////// 70 char * 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 } 117 94 } 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 /////////////////////////////////////////// 97 char * 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 } 157 111 } 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 /////////////////////////////////////////// 114 char * 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 ///////////////////////////////////////////////////////////////////////////////////////// 137 static 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 144 thread_t * this = CURRENT_THREAD; 145 process_t * process = this->process; 146 pid_t socket_pid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid )); 147 fdid_t socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid )); 148 uint32_t cycle = (uint32_t)hal_get_cycles(); 149 if( DEBUG_SOCKET_LINK < cycle ) 150 printk("\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 185 cycle = (uint32_t)hal_get_cycles(); 186 if( DEBUG_SOCKET_LINK < cycle ) 187 printk("\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 ///////////////////////////////////////////////////////////////////////////////////////// 199 static 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 205 thread_t * this = CURRENT_THREAD; 206 process_t * process = this->process; 207 pid_t socket_pid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid )); 208 fdid_t socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid )); 209 uint32_t cycle = (uint32_t)hal_get_cycles(); 210 if( DEBUG_SOCKET_LINK < cycle ) 211 printk("\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 247 cycle = (uint32_t)hal_get_cycles(); 248 if( DEBUG_SOCKET_LINK < cycle ) 249 printk("\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 ///////////////////////////////////////////////////////////////////////////////////////// 272 static 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 290 uint32_t cycle = (uint32_t)hal_get_cycles(); 291 if( DEBUG_SOCKET_CREATE < cycle ) 292 printk("\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 398 if( DEBUG_SOCKET_CREATE < cycle ) 399 printk("\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 ///////////////////////////////////////////////////////////////////////////////////////// 421 static 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 429 assert( (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 436 uint32_t cycle = (uint32_t)hal_get_cycles(); 437 if( DEBUG_SOCKET_DESTROY < cycle ) 438 printk("\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 447 assert( (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 478 cycle = (uint32_t)hal_get_cycles(); 479 if( DEBUG_SOCKET_DESTROY < cycle ) 480 printk("\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 //////////////////////////////////////////////// 487 void 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 ); 216 514 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 /////////////////////////////////////////////////// 528 error_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 //////////////////////////////////////////////////// 549 error_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 ////////////////////////////////////// 578 int 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 586 uint32_t cycle = (uint32_t)hal_get_cycles(); 587 thread_t * this = CURRENT_THREAD; 588 process_t * process = this->process; 589 if( DEBUG_SOCKET_BUILD < cycle ) 590 printk("\n[%s] thread[%x,%x] enter / %s / %s / cycle %d\n", 591 __FUNCTION__, process->pid, this->trdid, 592 socket_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 604 cycle = (uint32_t)hal_get_cycles(); 605 if( DEBUG_SOCKET_BUILD < cycle ) 606 printk("\n[%s] thread[%x,%x] exit / socket %x / fdid %d / %s / cycle %d\n", 607 __FUNCTION__, process->pid, this->trdid, socket, fdid, 608 socket_state_str(hal_remote_l32(XPTR(local_cxy , &socket->state))), 609 cycle ); 610 #endif 611 612 if( error ) return -1; 613 return fdid; 614 } 615 616 //////////////////////////////// 617 int 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 630 uint32_t cycle = (uint32_t)hal_get_cycles(); 631 if( DEBUG_SOCKET_BIND < cycle ) 632 printk("\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 672 cycle = (uint32_t)hal_get_cycles(); 673 if( DEBUG_SOCKET_BIND < cycle ) 674 printk("\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, 676 socket_state_str(hal_remote_l32( XPTR( file_cxy , &socket->state ))), 677 hal_remote_l32( XPTR( file_cxy , &socket->local_addr )), 678 hal_remote_l32( XPTR( file_cxy , &socket->local_port )), 679 cycle ); 680 #endif 681 682 return 0; 683 684 } // end socket_bind() 685 686 ////////////////////////////////// 687 int 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 705 uint32_t cycle = (uint32_t)hal_get_cycles(); 706 if( DEBUG_SOCKET_LISTEN < cycle ) 707 printk("\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 791 cycle = (uint32_t)hal_get_cycles(); 792 if( DEBUG_SOCKET_LISTEN < cycle ) 793 printk("\n[%s] thread[%x,%x] exit / socket[%x,%d] / %s / cycle %d\n", 794 __FUNCTION__, process->pid, this->trdid, process->pid, fdid, 795 socket_state_str(socket_state), cycle ); 796 #endif 797 798 return 0; 799 800 } // end socket_listen() 801 802 /////////////////////////////////// 803 int 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 845 uint32_t cycle = (uint32_t)hal_get_cycles(); 846 if( DEBUG_SOCKET_ACCEPT < cycle ) 847 printk("\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 955 cycle = (uint32_t)hal_get_cycles(); 956 if( DEBUG_SOCKET_ACCEPT < cycle ) 957 printk("\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 965 cycle = (uint32_t)hal_get_cycles(); 966 if( DEBUG_SOCKET_ACCEPT < cycle ) 967 printk("\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 978 assert( (((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 1001 assert( (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 1016 cycle = (uint32_t)hal_get_cycles(); 1017 if( DEBUG_SOCKET_ACCEPT < cycle ) 1018 printk("\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 1042 cycle = (uint32_t)hal_get_cycles(); 1043 if( DEBUG_SOCKET_ACCEPT < cycle ) 1044 printk("\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 1086 cycle = (uint32_t)hal_get_cycles(); 1087 if( DEBUG_SOCKET_ACCEPT < cycle ) 1088 printk("\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 1097 cycle = (uint32_t)hal_get_cycles(); 1098 if( DEBUG_SOCKET_ACCEPT < cycle ) 1099 printk("\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 1108 assert( (((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 1125 cycle = (uint32_t)hal_get_cycles(); 1126 if( DEBUG_SOCKET_ACCEPT < cycle ) 1127 printk("\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, 1129 socket_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 ////////////////////////////////// 1141 int 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 1177 uint32_t cycle = (uint32_t)hal_get_cycles(); 1178 pid_t pid = this->process->pid; 1179 trdid_t trdid = this->trdid; 1180 if( DEBUG_SOCKET_CONNECT < cycle ) 1181 printk("\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 1266 cycle = (uint32_t)hal_get_cycles(); 1267 if( DEBUG_SOCKET_CONNECT < cycle ) 1268 printk("\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 1276 cycle = (uint32_t)hal_get_cycles(); 1277 if( DEBUG_SOCKET_CONNECT < cycle ) 1278 printk("\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 1287 assert( (((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 1304 cycle = (uint32_t)hal_get_cycles(); 1305 if( DEBUG_SOCKET_CONNECT < cycle ) 1306 printk("\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 /////////////////////////////////// 1316 int 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 1337 assert( (hal_remote_l32( XPTR( file_cxy , &socket_ptr->fdid )) == fdid), 1338 "unconsistent file_xp & fdid arguments"); 1339 1340 #if DEBUG_SOCKET_CLOSE 1341 uint32_t cycle = (uint32_t)hal_get_cycles(); 1342 pid_t pid = this->process->pid; 1343 if (DEBUG_SOCKET_CLOSE < cycle ) 1344 printk("\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 1380 cycle = (uint32_t)hal_get_cycles(); 1381 if( cycle > DEBUG_DEV_NIC_TX ) 1382 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / destroy socket / cycle %d\n", 1383 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 1384 socket_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 1397 cycle = (uint32_t)hal_get_cycles(); 1398 if( cycle > DEBUG_DEV_NIC_TX ) 1399 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / destroy socket / cycle %d\n", 1400 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 1401 socket_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 1431 cycle = (uint32_t)hal_get_cycles(); 1432 if( DEBUG_SOCKET_CLOSE < cycle ) 1433 printk("\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 1441 cycle = (uint32_t)hal_get_cycles(); 1442 if( DEBUG_SOCKET_CLOSE < cycle ) 1443 printk("\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 1454 assert( (((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", 1458 socket_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 1473 cycle = (uint32_t)hal_get_cycles(); 1474 if( DEBUG_SOCKET_CLOSE < cycle ) 1475 printk("\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 //////////////////////////////////////////////////////////////////////////////////////// 1513 int 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 1639 uint32_t cycle = (uint32_t)hal_get_cycles(); 1640 if (DEBUG_SOCKET_SEND < cycle ) 1641 printk("\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 1701 cycle = (uint32_t)hal_get_cycles(); 1702 if( DEBUG_SOCKET_SEND < cycle ) 1703 printk("\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 1711 cycle = (uint32_t)hal_get_cycles(); 1712 if( DEBUG_SOCKET_SEND < cycle ) 1713 printk("\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 1731 assert( (((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", 1734 tx_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 1744 cycle = (uint32_t)hal_get_cycles(); 1745 if( DEBUG_SOCKET_RECV < cycle ) 1746 printk("\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 1755 cycle = (uint32_t)hal_get_cycles(); 1756 if (DEBUG_SOCKET_SEND < cycle ) 1757 printk("\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 1770 uint32_t cycle = (uint32_t)hal_get_cycles(); 1771 if (DEBUG_SOCKET_SEND < cycle ) 1772 printk("\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 1794 uint32_t cycle = (uint32_t)hal_get_cycles(); 1795 if( DEBUG_SOCKET_RECV < cycle ) 1796 printk("\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 1818 uint32_t cycle = (uint32_t)hal_get_cycles(); 1819 if( DEBUG_SOCKET_RECV < cycle ) 1820 printk("\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 1828 cycle = (uint32_t)hal_get_cycles(); 1829 if( DEBUG_SOCKET_RECV < cycle ) 1830 printk("\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 1841 assert( (((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", 1844 buf_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 1859 cycle = (uint32_t)hal_get_cycles(); 1860 if( DEBUG_SOCKET_RECV < cycle ) 1861 printk("\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 1870 cycle = (uint32_t)hal_get_cycles(); 1871 if( DEBUG_SOCKET_RECV < cycle ) 1872 printk("\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 1888 cycle = (uint32_t)hal_get_cycles(); 1889 if (DEBUG_SOCKET_SEND < cycle ) 1890 printk("\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 /////////////////////////////////// 1900 int 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 ///////////////////////////////////// 1914 int 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 /////////////////////////////////// 1932 int 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 /////////////////////////////////////// 1947 int 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 //////////////////////////////////////////// 1965 void 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 1 1 /* 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) 5 5 * 6 6 * Copyright (c) UPMC Sorbonne Universites 7 7 * 8 * This file is part of ALMOS-MKH .9 * 10 * ALMOS-MKH .is free software; you can redistribute it and/or modify it8 * This file is part of ALMOS-MKH 9 * 10 * ALMOS-MKH is free software; you can redistribute it and/or modify it 11 11 * under the terms of the GNU General Public License as published by 12 12 * the Free Software Foundation; version 2.0 of the License. 13 13 * 14 * ALMOS-MKH .is distributed in the hope that it will be useful, but14 * ALMOS-MKH is distributed in the hope that it will be useful, but 15 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU … … 18 18 * 19 19 * You should have received a copy of the GNU General Public License 20 * along with ALMOS-MKH .; if not, write to the Free Software Foundation,20 * along with ALMOS-MKH; if not, write to the Free Software Foundation, 21 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 22 */ 23 23 24 #ifndef _KSOCKET_H_ 25 #define _KSOCKET_H_ 26 24 27 #include <kernel_config.h> 25 28 #include <hal_kernel_types.h> 26 #include <hal_remote.h> 27 #include <shared_socket.h> 28 #include <process.h> 29 #include <xlist.h> 29 30 #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 ****************************************************************************************/ 158 typedef enum socket_cmd_type_e 44 159 { 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) */ 53 167 } 54 55 ///////////////////////////////////////// 56 char * socket_state_str( uint32_t state ) 168 socket_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 ****************************************************************************************/ 176 typedef enum socket_cmd_sts_e 57 177 { 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, 79 184 } 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 ) 185 socket_cmd_sts_t; 186 187 /***************************************************************************************** 188 * This enum defines the set of tates for an UDP socket. 189 ****************************************************************************************/ 190 typedef enum udp_socket_state_e 87 191 { 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 } 196 udp_socket_state_t; 197 198 /***************************************************************************************** 199 * This enum defines the set of tates for an TCP socket. 200 ****************************************************************************************/ 201 typedef enum tcp_socket_state_e 219 202 { 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 } 217 tcp_socket_state_t; 218 219 /***************************************************************************************** 220 * This structure defines one connection request, registered in the CRQ queue. 221 ****************************************************************************************/ 222 typedef struct connect_request_s 264 223 { 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 } 229 connect_request_t; 230 231 /***************************************************************************************** 232 * This structure defines the socket descriptor. 233 ****************************************************************************************/ 234 typedef 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 } 277 socket_t; 278 279 /**************************************************************************************** 280 * This function returns a printable string for a socket domain. 281 **************************************************************************************** 282 * domain : AF_INET / AF_LOCAL 283 ***************************************************************************************/ 284 char * 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 ***************************************************************************************/ 291 char * 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 ***************************************************************************************/ 298 char * 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 ***************************************************************************************/ 305 char * 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 ***************************************************************************************/ 312 char * 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 ***************************************************************************************/ 331 void 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 ***************************************************************************************/ 348 error_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 ***************************************************************************************/ 366 error_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 ***************************************************************************************/ 378 void 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 ***************************************************************************************/ 399 int 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 ***************************************************************************************/ 415 int 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 ***************************************************************************************/ 442 int 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 ***************************************************************************************/ 484 int 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 ***************************************************************************************/ 518 int 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 ***************************************************************************************/ 543 int 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 ***************************************************************************************/ 560 int 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 ***************************************************************************************/ 588 int 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 ***************************************************************************************/ 605 int 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 ***************************************************************************************/ 625 int 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 589 589 { 590 590 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++; 592 596 593 597 // get pointers on TXT0 chdev … … 605 609 nolock_printk("\n***** %s *****\n", string ); 606 610 607 for ( line = 0 ; line < (size>>4); line++ )611 for ( line = 0 , byte = 0 ; line < nlines ; line++ ) 608 612 { 609 nolock_printk(" %X | %b %b %b %b | %b %b %b %b | %b %b %b %b | %b %b %b %b \n",610 b yte,613 nolock_printk(" %X | %b %b %b %b | %b %b %b %b | %b %b %b %b | %b %b %b %b |\n", 614 buffer + byte, 611 615 buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3], 612 616 buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7], -
trunk/kernel/kern/process.c
r657 r662 1077 1077 1078 1078 /////////////////////////////////////////// 1079 char * 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 /////////////////////////////////////////// 1079 1097 void process_fd_init( process_t * process ) 1080 1098 { … … 1085 1103 1086 1104 // initialize number of open files 1087 process->fd_array. current= 0;1105 process->fd_array.max = 0; 1088 1106 1089 1107 // initialize array … … 1101 1119 bool_t found; 1102 1120 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 1104 1125 1105 1126 // get target process cluster and local pointer … … 1107 1128 cxy_t process_cxy = GET_CXY( process_xp ); 1108 1129 1109 // check target process is referenceprocess1110 assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr-> ref_xp ) ) ),1111 " client process must be referenceprocess\n" );1130 // check target process is owner process 1131 assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ), 1132 "process must be owner process\n" ); 1112 1133 1113 1134 #if DEBUG_PROCESS_FD_REGISTER … … 1120 1141 #endif 1121 1142 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 ); 1124 1146 1125 1147 // take lock protecting reference fd_array … … 1128 1150 found = false; 1129 1151 1152 // get current value of max_fdid 1153 max = hal_remote_l32( max_xp ); 1154 1130 1155 for ( id = 0; id < CONFIG_PROCESS_FILE_MAX_NR ; id++ ) 1131 1156 { 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 ) 1134 1161 { 1135 // update referencefd_array1162 // update fd_array 1136 1163 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 1140 1172 *fdid = id; 1141 1173 found = true; … … 1165 1197 pid_t pid; // target process PID 1166 1198 lpid_t lpid; // target process LPID 1199 xptr_t file_xp; // extended pointer on file descriptor 1167 1200 xptr_t iter_xp; // iterator for list of process copies 1168 1201 xptr_t copy_xp; // extended pointer on process copy … … 1170 1203 cxy_t copy_cxy; // process copy cluster identifier 1171 1204 1172 // check process_xp argument1173 assert( (process_xp != XPTR_NULL), "process_xp argument cannot be XPTR_NULL");1174 1175 1205 // get target process cluster and local pointer 1176 1206 process_t * process_ptr = GET_PTR( process_xp ); 1177 1207 cxy_t process_cxy = GET_CXY( process_xp ); 1178 1208 1209 // check target process is owner process 1210 assert( (process_xp == hal_remote_l64( XPTR( process_cxy , &process_ptr->owner_xp ) ) ), 1211 "process must be owner process\n" ); 1212 1179 1213 // get target process pid and lpid 1180 1214 pid = hal_remote_l32( XPTR( process_cxy , &process_ptr->pid) ); 1181 1215 lpid = LPID_FROM_PID( pid ); 1182 1183 // get process descriptor in owner cluster and in reference cluster1184 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 cluster1188 assert( (process_xp == owner_xp), "target process must be in owner process\n" );1189 1216 1190 1217 #if DEBUG_PROCESS_FD_REMOVE … … 1196 1223 #endif 1197 1224 1225 // get extended pointer on file descriptor 1226 file_xp = hal_remote_l64( XPTR( process_cxy , &process_ptr->fd_array.array[fdid] )); 1227 1198 1228 // build extended pointers on list_of_copies root and lock (in owner cluster) 1199 1229 xptr_t copies_root_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_root[lpid] ); 1200 1230 xptr_t copies_lock_xp = XPTR( process_cxy , &LOCAL_CLUSTER->pmgr.copies_lock[lpid] ); 1201 1231 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 1210 1237 remote_queuelock_acquire( fd_lock_xp ); 1211 1238 1212 1239 // take the lock protecting the list of copies 1213 1240 remote_queuelock_acquire( copies_lock_xp ); 1241 1242 // get max value 1243 uint32_t max = hal_remote_l32( fd_max_xp ); 1214 1244 1215 1245 // loop on list of process copies … … 1223 1253 // release the fd_array entry in process copy 1224 1254 hal_remote_s64( XPTR( copy_cxy , ©_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 ); 1226 1262 1227 1263 // release the lock protecting reference fd_array … … 1240 1276 } // end process_fd_remove() 1241 1277 1242 //////////////////////////////////////////////// 1243 xptr_t process_fd_get_xptr( process_t * process, 1244 uint32_t fdid ) 1278 ////////////////////////////////////////////// 1279 void 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 1293 assert( (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 1297 thread_t * this = CURRENT_THREAD; 1298 uint32_t cycle = (uint32_t)hal_get_cycles(); 1299 if( DEBUG_PROCESS_FD_CLEAN_ALL < cycle ) 1300 printk("\n[%s] thread[%x,%x] enter for process %x / cycle %d\n", 1301 __FUNCTION__, this->process->pid, this->trdid, pid, cycle ); 1302 1303 process_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 1335 cycle = (uint32_t)hal_get_cycles(); 1336 if( DEBUG_PROCESS_FD_CLEAN_ALL < cycle ) 1337 printk("\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 ////////////////////////////////////////////////////////////// 1344 xptr_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 1350 assert( (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 /////////////////////////////////////////////////////////// 1359 xptr_t process_fd_get_xptr_from_local( process_t * process, 1360 uint32_t fdid ) 1245 1361 { 1246 1362 xptr_t file_xp; … … 1252 1368 if( file_xp == XPTR_NULL ) 1253 1369 { 1254 // get referenceprocess cluster and local pointer1255 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 referencefd_array1260 lock_xp = XPTR( ref_cxy , &ref_ptr->fd_array.lock );1261 1262 // take lock protecting referencefd_array1370 // 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 1263 1379 remote_queuelock_acquire( lock_xp ); 1264 1380 1265 1381 // 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; 1270 1388 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 1272 1394 remote_queuelock_release( lock_xp ); 1273 1395 } … … 1275 1397 return file_xp; 1276 1398 1277 } // end process_fd_get_xptr ()1399 } // end process_fd_get_xptr_from_local() 1278 1400 1279 1401 /////////////////////////////////////////// … … 1319 1441 bool_t process_fd_array_full( void ) 1320 1442 { 1321 // get extended pointer on referenceprocess1322 xptr_t ref_xp = CURRENT_THREAD->process->ref_xp;1323 1324 // get referenceprocess cluster and local pointer1325 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 referencefd_array1329 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 ); 1332 1454 } 1333 1455 1456 //////////////////////////////////////////// 1457 void 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() 1334 1528 1335 1529 //////////////////////////////////////////////////////////////////////////////////// -
trunk/kernel/kern/process.h
r657 r662 70 70 /********************************************************************************************* 71 71 * 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. 75 74 * The array size is defined by the CONFIG_PROCESS_FILE_MAX_NR parameter. 76 75 * 77 * NOTE: - Only the fd_array[] in the reference process contains acomplete list of open76 * NOTE: - Only the fd_array[] in the reference process contains the complete list of open 78 77 * 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 the80 * open files to speed the fdid to xptr translation, but the "lock" and " current78 * - 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" 81 80 * 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. 86 87 ********************************************************************************************/ 87 88 … … 89 90 { 90 91 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 */ 92 93 xptr_t array[CONFIG_PROCESS_FILE_MAX_NR]; /*! open file descriptors */ 93 94 } … … 278 279 /********************************************************************************************* 279 280 * This function releases all memory allocated for a process descriptor in the local cluster, 280 * including memory allocated for embedded sub structures (fd_array, vmm, etc).281 * including memory allocated for embedded sub-structures (fd_array, vmm, etc). 281 282 * The local th_tbl[] array must be empty. 282 283 ********************************************************************************************* … … 428 429 429 430 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 ********************************************************************************************/ 440 char * process_fd_type_str( uint32_t type ); 431 441 432 442 /********************************************************************************************* 433 443 * This function initializes all entries of the local fd_array as empty. 434 444 ********************************************************************************************* 435 * @ process : pointer on the local process descriptor.445 * @ process : [in] pointer on the local process descriptor. 436 446 ********************************************************************************************/ 437 447 void process_fd_init( process_t * process ); 438 448 439 449 /********************************************************************************************* 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. 446 457 ********************************************************************************************* 447 458 * @ process_xp : [in] extended pointer on client reference process. 448 459 * @ 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 EMFILEif array full.460 * @ fdid : [out] buffer for allocated fd_array slot index. 461 * @ return 0 if success / return -1 if array full. 451 462 ********************************************************************************************/ 452 463 error_t process_fd_register( xptr_t process_xp, … … 455 466 456 467 /********************************************************************************************* 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, 458 469 * identified by the <fdid> argument, in all clusters containing a copy of the 459 470 * 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. 460 473 * 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. 466 478 ********************************************************************************************/ 467 479 void process_fd_remove( xptr_t process_xp, … … 469 481 470 482 /********************************************************************************************* 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 ********************************************************************************************/ 493 void 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. 473 499 * It accesses first the local process descriptor. In case of local miss, it takes 474 500 * 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. 480 505 * @ fdid : file descriptor index in the fd_array. 481 506 * @ return extended pointer on file descriptor if success / return XPTR_NULL if not found. 482 507 ********************************************************************************************/ 483 xptr_t process_fd_get_xptr( process_t * process, 484 uint32_t fdid ); 508 xptr_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 ********************************************************************************************/ 521 xptr_t process_fd_get_xptr_from_owner( xptr_t process_xp, 522 uint32_t fdid ); 485 523 486 524 /********************************************************************************************* … … 508 546 bool_t process_fd_array_full( void ); 509 547 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 ********************************************************************************************/ 555 void process_fd_display( xptr_t process_xp ); 511 556 512 557 /******************** Thread Related Operations *****************************************/ -
trunk/kernel/kern/scheduler.h
r640 r662 2 2 * scheduler.h - Core scheduler definition. 3 3 * 4 * Author Alain Greiner (2016,2017,2018 )4 * Author Alain Greiner (2016,2017,2018,2019,2020) 5 5 * 6 6 * Copyright (c) UPMC Sorbonne Universites -
trunk/kernel/kern/thread.c
r651 r662 3 3 * 4 4 * Author Ghassan Almaless (2008,2009,2010,2011,2012) 5 * Alain Greiner (2016,2017,2018,2019 )5 * Alain Greiner (2016,2017,2018,2019,2020) 6 6 * 7 7 * Copyright (c) UPMC Sorbonne Universites … … 831 831 hal_cpu_context_init( thread ); 832 832 833 // set THREAD_BLOCKED_IDLE for DEV threads834 if( type == THREAD_DEV ) thread->blocked |= THREAD_BLOCKED_IDLE;835 836 833 #if DEBUG_THREAD_KERNEL_CREATE 837 834 cycle = (uint32_t)hal_get_cycles(); -
trunk/kernel/kern/thread.h
r657 r662 87 87 #define THREAD_BLOCKED_JOIN 0x0010 /*! USR : blocked in exit / wait join */ 88 88 #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 */ 91 91 #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 */ 93 93 #define THREAD_BLOCKED_ISR 0x0400 /*! DEV : wait hardware IRQ */ 94 94 #define THREAD_BLOCKED_WAIT 0x0800 /*! USR : wait child process termination */ 95 95 #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 */ 97 97 98 98 /*************************************************************************************** … … 195 195 uint32_t busylocks; /*! number of taken busylocks */ 196 196 197 #if DEBUG_BUSYLOCK 197 #if DEBUG_BUSYLOCK_TYPE 198 198 xlist_entry_t busylocks_root; /*! root of xlist of taken busylocks */ 199 199 #endif
Note: See TracChangeset
for help on using the changeset viewer.