async_sess.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00100 #include <async_sess.h>
00101 #include <fibril_synch.h>
00102 #include <adt/list.h>
00103 #include <adt/hash_table.h>
00104 #include <malloc.h>
00105 #include <errno.h>
00106 #include <assert.h>
00107 #include <async.h>
00108 #include "private/async_sess.h"
00109 
00111 typedef struct {
00112         link_t sess_link;       
00113         link_t global_link;     
00114         int data_phone;         
00115 } conn_node_t;
00116 
00121 static fibril_mutex_t async_sess_mutex;
00122 
00126 static LIST_INITIALIZE(inactive_conn_head);
00127 
00131 static LIST_INITIALIZE(session_list_head);
00132 
00136 static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
00137 
00143 void __async_sess_init(void)
00144 {
00145         fibril_mutex_initialize(&async_sess_mutex);
00146         list_initialize(&inactive_conn_head);
00147         list_initialize(&session_list_head);
00148 }
00149 
00165 void async_session_create(async_sess_t *sess, int phone, sysarg_t arg1)
00166 {
00167         sess->sess_phone = phone;
00168         sess->connect_arg1 = arg1;
00169         list_initialize(&sess->conn_head);
00170         
00171         /* Add to list of sessions. */
00172         fibril_mutex_lock(&async_sess_mutex);
00173         list_append(&sess->sess_link, &session_list_head);
00174         fibril_mutex_unlock(&async_sess_mutex);
00175 }
00176 
00184 void async_session_destroy(async_sess_t *sess)
00185 {
00186         conn_node_t *conn;
00187 
00188         /* Remove from list of sessions. */
00189         fibril_mutex_lock(&async_sess_mutex);
00190         list_remove(&sess->sess_link);
00191         fibril_mutex_unlock(&async_sess_mutex);
00192 
00193         /* We did not connect the phone so we do not hang it up either. */
00194         sess->sess_phone = -1;
00195 
00196         /* Tear down all data connections. */
00197         while (!list_empty(&sess->conn_head)) {
00198                 conn = list_get_instance(sess->conn_head.next, conn_node_t,
00199                     sess_link);
00200 
00201                 list_remove(&conn->sess_link);
00202                 list_remove(&conn->global_link);
00203                 
00204                 async_hangup(conn->data_phone);
00205                 free(conn);
00206         }
00207         
00208         fibril_condvar_broadcast(&avail_phone_cv);
00209 }
00210 
00211 static void conn_node_initialize(conn_node_t *conn)
00212 {
00213         link_initialize(&conn->sess_link);
00214         link_initialize(&conn->global_link);
00215         conn->data_phone = -1;
00216 }
00217 
00224 int async_exchange_begin(async_sess_t *sess)
00225 {
00226         conn_node_t *conn;
00227         int data_phone;
00228 
00229         fibril_mutex_lock(&async_sess_mutex);
00230 
00231         if (!list_empty(&sess->conn_head)) {
00232                 /*
00233                  * There are inactive connections in the session.
00234                  */
00235                 conn = list_get_instance(sess->conn_head.next, conn_node_t,
00236                     sess_link);
00237                 list_remove(&conn->sess_link);
00238                 list_remove(&conn->global_link);
00239                 
00240                 data_phone = conn->data_phone;
00241                 free(conn);
00242         } else {
00243                 /*
00244                  * There are no available connections in the session.
00245                  * Make a one-time attempt to connect a new data phone.
00246                  */
00247 retry:
00248                 data_phone = async_connect_me_to(sess->sess_phone,
00249                     sess->connect_arg1, 0, 0);
00250                 if (data_phone >= 0) {
00251                         /* success, do nothing */
00252                 } else if (!list_empty(&inactive_conn_head)) {
00253                         /*
00254                          * We did not manage to connect a new phone. But we can
00255                          * try to close some of the currently inactive
00256                          * connections in other sessions and try again.
00257                          */
00258                         conn = list_get_instance(inactive_conn_head.next,
00259                             conn_node_t, global_link);
00260                         list_remove(&conn->global_link);
00261                         list_remove(&conn->sess_link);
00262                         data_phone = conn->data_phone;
00263                         free(conn);
00264                         async_hangup(data_phone);
00265                         goto retry;
00266                 } else {
00267                         /*
00268                          * Wait for a phone to become available.
00269                          */
00270                         fibril_condvar_wait(&avail_phone_cv, &async_sess_mutex);
00271                         goto retry;
00272                 }
00273         }
00274 
00275         fibril_mutex_unlock(&async_sess_mutex);
00276         return data_phone;
00277 }
00278 
00284 void async_exchange_end(async_sess_t *sess, int data_phone)
00285 {
00286         conn_node_t *conn;
00287 
00288         fibril_mutex_lock(&async_sess_mutex);
00289         fibril_condvar_signal(&avail_phone_cv);
00290         conn = (conn_node_t *) malloc(sizeof(conn_node_t));
00291         if (!conn) {
00292                 /*
00293                  * Being unable to remember the connected data phone here
00294                  * means that we simply hang up.
00295                  */
00296                 async_hangup(data_phone);
00297                 fibril_mutex_unlock(&async_sess_mutex);
00298                 return;
00299         }
00300 
00301         conn_node_initialize(conn);
00302         conn->data_phone = data_phone;
00303         list_append(&conn->sess_link, &sess->conn_head);
00304         list_append(&conn->global_link, &inactive_conn_head);
00305         fibril_mutex_unlock(&async_sess_mutex);
00306 }
00307 

Generated on Thu Jun 2 07:45:46 2011 for HelenOS/USB by  doxygen 1.4.7