Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 0edaf0f6 in mainline


Ignore:
Timestamp:
2011-12-16T18:04:30Z (10 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master
Children:
ab9378b4
Parents:
7a8c1c4e
Message:

Revamp connection synchronization.

Location:
uspace/srv/net/tl/tcp
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/tl/tcp/conn.c

    r7a8c1c4e r0edaf0f6  
    5656
    5757LIST_INITIALIZE(conn_list);
     58FIBRIL_MUTEX_INITIALIZE(conn_list_lock);
    5859
    5960static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg);
     
    8182                goto error;
    8283
     84        fibril_mutex_initialize(&conn->lock);
     85
     86        /* One for the user, one for not being in closed state */
     87        atomic_set(&conn->refcnt, 2);
     88
    8389        /* Allocate receive buffer */
    84         fibril_mutex_initialize(&conn->rcv_buf_lock);
    8590        fibril_condvar_initialize(&conn->rcv_buf_cv);
    8691        conn->rcv_buf_size = RCV_BUF_SIZE;
     
    9398
    9499        /** Allocate send buffer */
    95         fibril_mutex_initialize(&conn->snd_buf_lock);
    96100        fibril_condvar_initialize(&conn->snd_buf_cv);
    97101        conn->snd_buf_size = SND_BUF_SIZE;
     
    115119
    116120        /* Connection state change signalling */
    117         fibril_mutex_initialize(&conn->cstate_lock);
    118121        fibril_condvar_initialize(&conn->cstate_cv);
    119122
     
    146149/** Destroy connection structure.
    147150 *
    148  * Connection structure should be destroyed when both of two conditions are
    149  * met: (1) user has deleted the connection and (2) the connection has entered
    150  * closed state.
     151 * Connection structure should be destroyed when the folowing condtitions
     152 * are met:
     153 * (1) user has deleted the connection
     154 * (2) the connection has entered closed state
     155 * (3) nobody is holding references to the connection
     156 *
     157 * This happens when @a conn->refcnt is zero as we count (1) and (2)
     158 * as special references.
    151159 *
    152160 * @param conn          Connection
     
    166174}
    167175
     176/** Add reference to connection.
     177 *
     178 * Increase connection reference count by one.
     179 *
     180 * @param conn          Connection
     181 */
     182void tcp_conn_addref(tcp_conn_t *conn)
     183{
     184        log_msg(LVL_DEBUG, "%s: tcp_conn_addref(%p)", conn->name, conn);
     185        atomic_inc(&conn->refcnt);
     186}
     187
     188/** Remove reference from connection.
     189 *
     190 * Decrease connection reference count by one.
     191 *
     192 * @param conn          Connection
     193 */
     194void tcp_conn_delref(tcp_conn_t *conn)
     195{
     196        log_msg(LVL_DEBUG, "%s: tcp_conn_delref(%p)", conn->name, conn);
     197
     198        if (atomic_predec(&conn->refcnt) == 0)
     199                tcp_conn_free(conn);
     200}
     201
    168202/** Delete connection.
    169203 *
     
    175209void tcp_conn_delete(tcp_conn_t *conn)
    176210{
    177         fibril_mutex_lock(&conn->cstate_lock);
    178         conn->deleted = true;
    179 
    180         if (conn->cstate == st_closed) {
    181                 fibril_mutex_unlock(&conn->cstate_lock);
    182                 tcp_conn_free(conn);
    183         } else {
    184                 fibril_mutex_unlock(&conn->cstate_lock);
    185         }
     211        log_msg(LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
     212
     213        assert(conn->deleted == false);
     214        tcp_conn_delref(conn);
    186215}
    187216
     
    192221void tcp_conn_add(tcp_conn_t *conn)
    193222{
     223        fibril_mutex_lock(&conn_list_lock);
    194224        list_append(&conn->link, &conn_list);
     225        fibril_mutex_unlock(&conn_list_lock);
    195226}
    196227
     
    201232void tcp_conn_remove(tcp_conn_t *conn)
    202233{
     234        fibril_mutex_lock(&conn_list_lock);
    203235        list_remove(&conn->link);
     236        fibril_mutex_unlock(&conn_list_lock);
    204237}
    205238
    206239static void tcp_conn_state_set(tcp_conn_t *conn, tcp_cstate_t nstate)
    207240{
    208         fibril_mutex_lock(&conn->cstate_lock);
     241        tcp_cstate_t old_state;
     242
     243        old_state = conn->cstate;
    209244        conn->cstate = nstate;
    210245        fibril_condvar_broadcast(&conn->cstate_cv);
    211246
    212         if (nstate == st_closed && conn->deleted) {
    213                 fibril_mutex_unlock(&conn->cstate_lock);
    214                 tcp_conn_free(conn);
    215         } else {
    216                 fibril_mutex_unlock(&conn->cstate_lock);
     247        assert(old_state != st_closed);
     248        if (nstate == st_closed) {
     249                /* Drop one reference for now being in closed state */
     250                tcp_conn_delref(conn);
    217251        }
    218252}
     
    302336 * A connection is uniquely identified by a socket pair. Look up our
    303337 * connection map and return connection structure based on socket pair.
     338 * The connection reference count is bumped by one.
    304339 *
    305340 * @param sp    Socket pair
    306341 * @return      Connection structure or NULL if not found.
    307342 */
    308 tcp_conn_t *tcp_conn_find(tcp_sockpair_t *sp)
     343tcp_conn_t *tcp_conn_find_ref(tcp_sockpair_t *sp)
    309344{
    310345        log_msg(LVL_DEBUG, "tcp_conn_find(%p)", sp);
     346
     347        fibril_mutex_lock(&conn_list_lock);
    311348
    312349        list_foreach(conn_list, link) {
     
    317354                    csp->local.addr.ipv4, csp->local.port);
    318355                if (tcp_sockpair_match(sp, csp)) {
     356                        tcp_conn_addref(conn);
     357                        fibril_mutex_unlock(&conn_list_lock);
    319358                        return conn;
    320359                }
    321360        }
    322361
     362        fibril_mutex_unlock(&conn_list_lock);
    323363        return NULL;
    324364}
     
    910950        tcp_conn_trim_seg_to_wnd(conn, seg);
    911951
    912         fibril_mutex_lock(&conn->rcv_buf_lock);
    913 
    914952        /* Determine how many bytes to copy */
    915953        text_size = tcp_segment_text_size(seg);
     
    923961        /* Signal to the receive function that new data has arrived */
    924962        fibril_condvar_broadcast(&conn->rcv_buf_cv);
    925         fibril_mutex_unlock(&conn->rcv_buf_lock);
    926963
    927964        log_msg(LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
     
    10131050
    10141051                /* Add FIN to the receive buffer */
    1015                 fibril_mutex_lock(&conn->rcv_buf_lock);
    10161052                conn->rcv_buf_fin = true;
    10171053                fibril_condvar_broadcast(&conn->rcv_buf_cv);
    1018                 fibril_mutex_unlock(&conn->rcv_buf_lock);
    10191054
    10201055                tcp_segment_delete(seg);
     
    11251160        log_msg(LVL_DEBUG, "tw_timeout_func(%p)", conn);
    11261161
     1162        fibril_mutex_lock(&conn->lock);
     1163
    11271164        if (conn->cstate == st_closed) {
    11281165                log_msg(LVL_DEBUG, "Connection already closed.");
     1166                fibril_mutex_unlock(&conn->lock);
     1167                tcp_conn_delref(conn);
    11291168                return;
    11301169        }
     
    11331172        tcp_conn_remove(conn);
    11341173        tcp_conn_state_set(conn, st_closed);
     1174
     1175        fibril_mutex_unlock(&conn->lock);
     1176        tcp_conn_delref(conn);
    11351177}
    11361178
     
    11411183void tcp_conn_tw_timer_set(tcp_conn_t *conn)
    11421184{
     1185        tcp_conn_addref(conn);
    11431186        fibril_timer_set(conn->tw_timer, TIME_WAIT_TIMEOUT, tw_timeout_func,
    11441187            (void *)conn);
     
    11511194void tcp_conn_tw_timer_clear(tcp_conn_t *conn)
    11521195{
    1153         fibril_timer_clear(conn->tw_timer);
     1196        if (fibril_timer_clear(conn->tw_timer) == fts_active)
     1197                tcp_conn_delref(conn);
    11541198}
    11551199
  • uspace/srv/net/tl/tcp/conn.h

    r7a8c1c4e r0edaf0f6  
    4646extern void tcp_conn_fin_sent(tcp_conn_t *);
    4747extern void tcp_conn_ack_of_fin_rcvd(tcp_conn_t *);
    48 extern tcp_conn_t *tcp_conn_find(tcp_sockpair_t *);
     48extern tcp_conn_t *tcp_conn_find_ref(tcp_sockpair_t *);
     49extern void tcp_conn_addref(tcp_conn_t *);
     50extern void tcp_conn_delref(tcp_conn_t *);
    4951extern bool tcp_conn_got_syn(tcp_conn_t *);
    5052extern void tcp_conn_segment_arrived(tcp_conn_t *, tcp_segment_t *);
  • uspace/srv/net/tl/tcp/tcp_type.h

    r7a8c1c4e r0edaf0f6  
    162162        acpass_t ap;
    163163
     164        /** Protects access to connection structure */
     165        fibril_mutex_t lock;
     166        /** Reference count */
     167        atomic_t refcnt;
     168
    164169        /** Connection state */
    165170        tcp_cstate_t cstate;
     
    168173        /** True if connection was deleted by user */
    169174        bool deleted;
    170         /** Protects @c cstate */
    171         fibril_mutex_t cstate_lock;
    172175        /** Signalled when @c cstate changes */
    173176        fibril_condvar_t cstate_cv;
     
    193196        /** Receive buffer contains FIN */
    194197        bool rcv_buf_fin;
    195         /** Receive buffer lock */
    196         fibril_mutex_t rcv_buf_lock;
    197198        /** Receive buffer CV. Broadcast when new data is inserted */
    198199        fibril_condvar_t rcv_buf_cv;
     
    206207        /** Send buffer contains FIN */
    207208        bool snd_buf_fin;
    208         /** Send buffer lock */
    209         fibril_mutex_t snd_buf_lock;
    210209        /** Send buffer CV. Broadcast when space is made available in buffer */
    211210        fibril_condvar_t snd_buf_cv;
  • uspace/srv/net/tl/tcp/tqueue.c

    r7a8c1c4e r0edaf0f6  
    167167        log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
    168168
    169         fibril_mutex_lock(&conn->snd_buf_lock);
    170 
    171169        /* Number of free sequence numbers in send window */
    172170        avail_wnd = (conn->snd_una + conn->snd_wnd) - conn->snd_nxt;
     
    178176            xfer_seqlen);
    179177
    180         if (xfer_seqlen == 0) {
    181                 fibril_mutex_unlock(&conn->snd_buf_lock);
    182                 return;
    183         }
     178        if (xfer_seqlen == 0)
     179                return;
    184180
    185181        /* XXX Do not always send immediately */
     
    198194        seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
    199195        if (seg == NULL) {
    200                 fibril_mutex_unlock(&conn->snd_buf_lock);
    201196                log_msg(LVL_ERROR, "Memory allocation failure.");
    202197                return;
     
    212207
    213208        fibril_condvar_broadcast(&conn->snd_buf_cv);
    214         fibril_mutex_unlock(&conn->snd_buf_lock);
    215209
    216210        if (send_fin)
     
    323317        log_msg(LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
    324318
     319        fibril_mutex_lock(&conn->lock);
     320
    325321        if (conn->cstate == st_closed) {
    326322                log_msg(LVL_DEBUG, "Connection already closed.");
     323                fibril_mutex_unlock(&conn->lock);
     324                tcp_conn_delref(conn);
    327325                return;
    328326        }
     
    331329        if (link == NULL) {
    332330                log_msg(LVL_DEBUG, "Nothing to retransmit");
     331                fibril_mutex_unlock(&conn->lock);
     332                tcp_conn_delref(conn);
    333333                return;
    334334        }
     
    339339        if (rt_seg == NULL) {
    340340                log_msg(LVL_ERROR, "Memory allocation failed.");
     341                fibril_mutex_unlock(&conn->lock);
     342                tcp_conn_delref(conn);
    341343                /* XXX Handle properly */
    342344                return;
     
    348350        /* Reset retransmission timer */
    349351        tcp_tqueue_timer_set(tqe->conn);
     352
     353        fibril_mutex_unlock(&conn->lock);
     354        tcp_conn_delref(conn);
    350355}
    351356
     
    355360        log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
    356361
    357         (void) retransmit_timeout_func;
     362        /* Clear first to make sure we update refcnt correctly */
     363        tcp_tqueue_timer_clear(conn);
     364
     365        tcp_conn_addref(conn);
    358366        fibril_timer_set(conn->retransmit.timer, RETRANSMIT_TIMEOUT,
    359367            retransmit_timeout_func, (void *) conn);
     
    365373        log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
    366374
    367         fibril_timer_clear(conn->retransmit.timer);
     375        if (fibril_timer_clear(conn->retransmit.timer) == fts_active)
     376                tcp_conn_delref(conn);
    368377}
    369378
  • uspace/srv/net/tl/tcp/ucall.c

    r7a8c1c4e r0edaf0f6  
    8383        /* Wait for connection to be established or reset */
    8484        log_msg(LVL_DEBUG, "tcp_uc_open: Wait for connection.");
    85         fibril_mutex_lock(&nconn->cstate_lock);
     85        fibril_mutex_lock(&nconn->lock);
    8686        while (nconn->cstate == st_listen ||
    8787            nconn->cstate == st_syn_sent ||
    8888            nconn->cstate == st_syn_received) {
    89                 fibril_condvar_wait(&nconn->cstate_cv, &nconn->cstate_lock);
     89                fibril_condvar_wait(&nconn->cstate_cv, &nconn->lock);
    9090        }
    9191
     
    9393                log_msg(LVL_DEBUG, "tcp_uc_open: Connection was reset.");
    9494                assert(nconn->cstate == st_closed);
    95                 fibril_mutex_unlock(&nconn->cstate_lock);
     95                fibril_mutex_unlock(&nconn->lock);
    9696                return TCP_ERESET;
    9797        }
    9898
    99         fibril_mutex_unlock(&nconn->cstate_lock);
     99        fibril_mutex_unlock(&nconn->lock);
    100100        log_msg(LVL_DEBUG, "tcp_uc_open: Connection was established.");
    101101
     
    113113        log_msg(LVL_DEBUG, "%s: tcp_uc_send()", conn->name);
    114114
    115         if (conn->cstate == st_closed)
     115        fibril_mutex_lock(&conn->lock);
     116
     117        if (conn->cstate == st_closed) {
     118                fibril_mutex_unlock(&conn->lock);
    116119                return TCP_ENOTEXIST;
     120        }
    117121
    118122        if (conn->cstate == st_listen) {
     
    121125        }
    122126
    123         fibril_mutex_lock(&conn->snd_buf_lock);
    124127
    125128        if (conn->snd_buf_fin) {
    126                 fibril_mutex_unlock(&conn->snd_buf_lock);
     129                fibril_mutex_unlock(&conn->lock);
    127130                return TCP_ECLOSING;
    128131        }
     
    133136                        log_msg(LVL_DEBUG, "%s: buf_free == 0, waiting.",
    134137                            conn->name);
    135                         fibril_condvar_wait(&conn->snd_buf_cv,
    136                             &conn->snd_buf_lock);
     138                        fibril_condvar_wait(&conn->snd_buf_cv, &conn->lock);
    137139                        buf_free = conn->snd_buf_size - conn->snd_buf_used;
    138140                }
    139141
    140142                if (conn->reset) {
    141                         fibril_mutex_unlock(&conn->snd_buf_lock);
     143                        fibril_mutex_unlock(&conn->lock);
    142144                        return TCP_ERESET;
    143145                }
     
    151153                size -= xfer_size;
    152154
    153                 fibril_mutex_unlock(&conn->snd_buf_lock);
    154155                tcp_tqueue_new_data(conn);
    155                 fibril_mutex_lock(&conn->snd_buf_lock);
    156         }
    157 
    158         fibril_mutex_unlock(&conn->snd_buf_lock);
     156        }
     157
    159158        tcp_tqueue_new_data(conn);
     159        fibril_mutex_unlock(&conn->lock);
    160160
    161161        return TCP_EOK;
     
    170170        log_msg(LVL_DEBUG, "%s: tcp_uc_receive()", conn->name);
    171171
    172         if (conn->cstate == st_closed)
     172        fibril_mutex_lock(&conn->lock);
     173
     174        if (conn->cstate == st_closed) {
     175                fibril_mutex_unlock(&conn->lock);
    173176                return TCP_ENOTEXIST;
    174 
    175         fibril_mutex_lock(&conn->rcv_buf_lock);
     177        }
    176178
    177179        /* Wait for data to become available */
    178180        while (conn->rcv_buf_used == 0 && !conn->rcv_buf_fin && !conn->reset) {
    179181                log_msg(LVL_DEBUG, "tcp_uc_receive() - wait for data");
    180                 fibril_condvar_wait(&conn->rcv_buf_cv, &conn->rcv_buf_lock);
     182                fibril_condvar_wait(&conn->rcv_buf_cv, &conn->lock);
    181183        }
    182184
    183185        if (conn->rcv_buf_used == 0) {
    184                 fibril_mutex_unlock(&conn->rcv_buf_lock);
    185 
    186186                *rcvd = 0;
    187187                *xflags = 0;
     
    189189                if (conn->rcv_buf_fin) {
    190190                        /* End of data, peer closed connection */
     191                        fibril_mutex_unlock(&conn->lock);
    191192                        return TCP_ECLOSING;
    192193                } else {
    193194                        /* Connection was reset */
    194195                        assert(conn->reset);
     196                        fibril_mutex_unlock(&conn->lock);
    195197                        return TCP_ERESET;
    196198                }
     
    208210        conn->rcv_wnd += xfer_size;
    209211
    210         fibril_mutex_unlock(&conn->rcv_buf_lock);
    211 
    212212        /* TODO */
    213213        *xflags = 0;
     
    219219            conn->name, xfer_size);
    220220
     221        fibril_mutex_unlock(&conn->lock);
     222
    221223        return TCP_EOK;
    222224}
     
    227229        log_msg(LVL_DEBUG, "%s: tcp_uc_close()", conn->name);
    228230
    229         if (conn->cstate == st_closed)
     231        fibril_mutex_lock(&conn->lock);
     232
     233        if (conn->cstate == st_closed) {
     234                fibril_mutex_unlock(&conn->lock);
    230235                return TCP_ENOTEXIST;
    231 
    232         if (conn->snd_buf_fin)
     236        }
     237
     238        if (conn->snd_buf_fin) {
     239                fibril_mutex_unlock(&conn->lock);
    233240                return TCP_ECLOSING;
     241        }
    234242
    235243        conn->snd_buf_fin = true;
    236244        tcp_tqueue_new_data(conn);
    237245
     246        fibril_mutex_unlock(&conn->lock);
    238247        return TCP_EOK;
    239248}
     
    276285            sp->local.addr.ipv4, sp->local.port);
    277286
    278         conn = tcp_conn_find(sp);
    279         if (conn != NULL && conn->cstate != st_closed) {
    280                 if (conn->ident.foreign.addr.ipv4 == TCP_IPV4_ANY)
    281                         conn->ident.foreign.addr.ipv4 = sp->foreign.addr.ipv4;
    282                 if (conn->ident.foreign.port == TCP_PORT_ANY)
    283                         conn->ident.foreign.port = sp->foreign.port;
    284                 if (conn->ident.local.addr.ipv4 == TCP_IPV4_ANY)
    285                         conn->ident.local.addr.ipv4 = sp->local.addr.ipv4;
    286 
    287                 tcp_conn_segment_arrived(conn, seg);
    288         } else {
    289                 if (conn == NULL)
    290                         log_msg(LVL_WARN, "No connection found.");
    291                 else
    292                         log_msg(LVL_WARN, "Connection is closed.");
     287        conn = tcp_conn_find_ref(sp);
     288        if (conn == NULL) {
     289                log_msg(LVL_WARN, "No connection found.");
    293290                tcp_unexpected_segment(sp, seg);
    294         }
     291                return;
     292        }
     293
     294        fibril_mutex_lock(&conn->lock);
     295
     296        if (conn->cstate == st_closed) {
     297                log_msg(LVL_WARN, "Connection is closed.");
     298                tcp_unexpected_segment(sp, seg);
     299                fibril_mutex_unlock(&conn->lock);
     300                tcp_conn_delref(conn);
     301                return;
     302        }
     303
     304        if (conn->ident.foreign.addr.ipv4 == TCP_IPV4_ANY)
     305                conn->ident.foreign.addr.ipv4 = sp->foreign.addr.ipv4;
     306        if (conn->ident.foreign.port == TCP_PORT_ANY)
     307                conn->ident.foreign.port = sp->foreign.port;
     308        if (conn->ident.local.addr.ipv4 == TCP_IPV4_ANY)
     309                conn->ident.local.addr.ipv4 = sp->local.addr.ipv4;
     310
     311        tcp_conn_segment_arrived(conn, seg);
     312
     313        fibril_mutex_unlock(&conn->lock);
     314        tcp_conn_delref(conn);
    295315}
    296316
Note: See TracChangeset for help on using the changeset viewer.