app.c

Go to the documentation of this file.
00001 /* $Id: app.c 13795 2004-02-18 22:34:26Z reuther $ */
00002 /*****************************************************************************/
00003 /*!
00004  * \file    dsi/lib/src/app.c
00005  *
00006  * \brief   DRROPS Stream Interface. Application stream implementation.
00007  *
00008  * \date    07/10/2000
00009  * \author  Lars Reuther <reuther@os.inf.tu-dresden.de>
00010  */
00011 /*****************************************************************************/
00012 
00013 /* L4/DROPS inclues */
00014 #include <l4/sys/types.h>
00015 #include <l4/sys/consts.h>
00016 #include <l4/env/errno.h>
00017 #include <l4/util/atomic.h>
00018 #include <l4/util/macros.h>
00019 
00020 /* library includes */
00021 #include <l4/dsi/dsi.h>
00022 #include "__event.h"
00023 #include "__stream.h"
00024 #include "__config.h"
00025 #include "__debug.h"
00026 #include "__app.h"
00027 
00028 /******************************************************************************
00029  * global structures                                                          *
00030  *****************************************************************************/
00031 
00032 //! stream descriptors
00033 static dsi_stream_t streams[DSI_MAX_STREAMS];
00034 
00035 //! next index to search for unused stream
00036 static int next_stream;
00037 
00038 /*!\brief Initialize stream table.
00039  * \ingroup internal
00040  */
00041 void
00042 dsi_init_streams(void)
00043 {
00044   int i;
00045 
00046   for (i = 0; i < DSI_MAX_STREAMS; i++)
00047     streams[i].flags = DSI_STREAM_UNUSED;
00048 }
00049 
00050 /*!\brief Find and allocate unused stream descriptor
00051  * \ingroup internal
00052  *
00053  * \return pointer to unused stream, \c NULL if no stream is available.
00054  */
00055 static dsi_stream_t *
00056 __allocate_stream(void)
00057 {
00058   int i = next_stream;
00059 
00060   /* search unused stream descriptor */
00061   do
00062     {
00063       if (l4util_cmpxchg32(&streams[i].flags,
00064                            DSI_STREAM_UNUSED,DSI_STREAM_USED))
00065         {
00066           /* found */
00067           next_stream = (i + 1) % DSI_MAX_STREAMS;
00068           break;
00069         }
00070       
00071       i = (i + 1) % DSI_MAX_STREAMS;
00072     }
00073   while (i != next_stream);
00074 
00075   if (i == next_stream)
00076     return NULL;
00077   else
00078     return &streams[i];
00079 }
00080 
00081 /*!\brief Check if \c stream is a valid stream descriptor.
00082  * \ingroup internal
00083  *
00084  * \param stream        stream descriptor
00085  * \retval "!0"         if stream points to valid stream descriptor
00086  * \retval 0            otherwise
00087  */
00088 int 
00089 dsi_is_valid_stream(dsi_stream_t * stream)
00090 {
00091   if (stream == NULL)
00092     return 0;
00093 
00094   return ((stream >= streams) &&
00095           (stream < &streams[DSI_MAX_STREAMS]) &&
00096           (stream->flags != DSI_STREAM_UNUSED));
00097 }
00098 
00099 /*!\brief Check if \c component is a valid component decription.
00100  * \ingroup internal
00101  *
00102  * \param component     component description
00103  * \retval "!0"         if component is valid description
00104  * \retval 0            otherwise
00105  */
00106 static int 
00107 dsi_is_valid_component(dsi_component_t * component)
00108 {
00109   if (component == NULL)
00110     return 0;
00111 
00112   return ((!l4_is_invalid_id(component->socketref.work_th)) &&
00113           (!l4_is_invalid_id(component->socketref.sync_th)) &&
00114           (component->connect != NULL));
00115 }
00116 
00117 /*!\brief Create application stream and connect send/receive component.
00118  * \ingroup stream
00119  *
00120  * \param sender        description of send component
00121  * \param receiver      description od receive component
00122  * \param ctrl          control area
00123  * \param data          data area
00124  *
00125  * \retval 0              success, created stream, \c stream contains stream
00126  *                        descriptor
00127  * \retval -L4_EINVAL     invalid component / dataspace descriptors
00128  * \retval -DSI_ECONNECT  connect call to sender or receiver failed
00129  * \retval -DSI_ENOSTREAM no stream descriptor available
00130  */
00131 int
00132 dsi_stream_create(dsi_component_t * sender, dsi_component_t * receiver,
00133                   l4dm_dataspace_t ctrl, l4dm_dataspace_t data,
00134                   dsi_stream_t ** stream)
00135 {
00136   int ret;
00137   dsi_stream_t * s;
00138 
00139   *stream = NULL;
00140  
00141   /* sanity checks */
00142   if (!dsi_is_valid_component(sender))
00143     {
00144       LOG_Error("DSI: invalid send component");
00145       return -L4_EINVAL;
00146     }
00147   
00148   if (!dsi_is_valid_component(receiver))
00149     {
00150       LOG_Error("DSI: invalid receive component");
00151       return -L4_EINVAL;
00152     }
00153 
00154   if (l4dm_is_invalid_ds(ctrl))
00155     {
00156       LOG_Error("DSI: invalid control area");
00157       return -L4_EINVAL;
00158     }
00159 
00160   if (l4dm_is_invalid_ds(data))
00161     {
00162       LOG_Error("DSI: invalid data area");
00163       return -L4_EINVAL;
00164     }
00165 
00166   /* allocate stream descriptor */
00167   s = __allocate_stream();
00168   if (s == NULL)
00169     {
00170       /* no stream descriptor available */
00171       LOG_Error("DSI: no stream descriptor available!");
00172       return -DSI_ENOSTREAM;
00173     }
00174 
00175   /* connect components */
00176   ret = sender->connect(sender,&receiver->socketref);
00177   if (ret)
00178     {
00179       LOG_Error("DSI: connect sender failed: %s (%d)",
00180                 l4env_errstr(ret),ret);
00181       s->flags = DSI_STREAM_UNUSED;
00182       return -DSI_ECONNECT;
00183     }
00184   
00185   ret = receiver->connect(receiver,&sender->socketref);
00186   if (ret)
00187     {
00188       LOG_Error("DSI: connect receiver failed: %s (%d)",
00189                 l4env_errstr(ret),ret);
00190       s->flags = DSI_STREAM_UNUSED;
00191       return -DSI_ECONNECT;
00192     }
00193   
00194   /* setup stream descriptor */
00195   s->sender = *sender;
00196   s->receiver = *receiver;
00197   s->ctrl = ctrl;
00198   s->data = data;
00199   s->__private = NULL;
00200 
00201   *stream = s;
00202 
00203   /* done */
00204   return 0;
00205 }
00206 
00207 /*!\brief Send start messages to send/receive components.
00208  * \ingroup stream
00209  *
00210  * \param stream      stream descriptor
00211  * \retval 0          success
00212  * \retval -L4_EINVAL invalid stream descriptor
00213  *
00214  * Conceptionally, this function starts the data transmission on a
00215  * stream. Technically, this function just calls the start-functions
00216  * of the send and receive component of the stream. They should be
00217  * implemented in a way that data transmission is started this way. It
00218  * is perfectly legal for a send component to already start its send
00219  * operation after dsi_stream_create() to achieve its preload needed
00220  * for real-time guarantees. But the send component may stop generating
00221  * packets after it achieved its preload until dsi_stream_start() is called.
00222  */
00223 int
00224 dsi_stream_start(dsi_stream_t * stream)
00225 {
00226   int ret;
00227 
00228   /* check stream descriptor */
00229   if (!dsi_is_valid_stream(stream))
00230     return -L4_EINVAL;
00231 
00232   /* send start message to receiver */
00233   if (stream->receiver.start != NULL)
00234     {
00235       ret = stream->receiver.start(&stream->receiver);
00236       if (ret)
00237         {
00238           LOG_Error("DSI: start receiver failed: %s (%d)",
00239                     l4env_errstr(ret),ret);
00240           return ret;
00241         }
00242     }
00243 
00244   /* send start message to sender */
00245   if (stream->sender.start != NULL)
00246     {
00247       ret = stream->sender.start(&stream->sender);
00248       if (ret)
00249         {
00250           LOG_Error("DSI: start sender failed: %s (%d)",
00251                     l4env_errstr(ret),ret);
00252           return ret;
00253         }
00254     }
00255   
00256   /* done */
00257   return 0;
00258 }
00259 
00260 /*!
00261  * \brief stop the transfer on a stream
00262  * \ingroup stream
00263  *
00264  * This function calls the stop-functions provided on dsi_stream_create()
00265  * to stop the data transfer. It is up to the two components to react in a
00266  * reasonable way, dsi does not check anything, it just calls the functions,
00267  * first sender, receiver then.
00268  *
00269  * \param stream stream descriptor
00270  * \retval 0            on success
00271  * \retval -L4_EINVAL   invalid stream descriptor
00272  */
00273 int
00274 dsi_stream_stop(dsi_stream_t * stream)
00275 {
00276   int ret;
00277 
00278   // check stream descriptor
00279   if (!dsi_is_valid_stream(stream))
00280     return -L4_EINVAL;
00281             
00282   /* send stop message to sender */
00283   LOGdL(DEBUG_STREAM,"calling sender (%x) to stop...",
00284         stream->sender.socketref.work_th.id.task);
00285 
00286   if (stream->sender.stop != NULL){
00287     ret = stream->sender.stop(&stream->sender);
00288     if (ret)
00289       {
00290         LOG_Error("DSI: stop sender failed: %s (%d)",
00291                   l4env_errstr(ret),ret);
00292         return ret;
00293       }
00294   }
00295 
00296   /* send stop message to receiver */
00297   LOGdL(DEBUG_STREAM,"calling receiver (%x) to stop...",
00298         stream->receiver.socketref.work_th.id.task);
00299 
00300   if (stream->receiver.stop != NULL){
00301     ret = stream->receiver.stop(&stream->receiver);
00302     if (ret)
00303       {
00304         LOG_Error("DSI: stop receiver failed: %s (%d)",
00305                   l4env_errstr(ret),ret);
00306         return ret;
00307       }
00308   }
00309 
00310   /* done */
00311   return 0;
00312 }
00313 
00314 /*****************************************************************************/
00315 /**
00316  * \brief Close stream
00317  * \ingroup stream
00318  * 
00319  * \param  stream        Stream descriptor
00320  *      
00321  * \return 0 on success (stream closed), error code otherwise:
00322  *         - \c -L4_EINVAL       invalid socket descriptor
00323  *         - \c -DSI_ECOMPONENT  component operation failed
00324  * 
00325  * We need two steps to close a stream:
00326  * 1. Stop the send and receive component. After the stop function returned
00327  *    we can be sure that a component stopped its processing and does not
00328  *    access stream data anymore.
00329  * 2. Close the sockets and the stream.  
00330  * These two steps are required to ensure that no resource are released in 
00331  * a component while the other component still uses them.
00332  */
00333 /*****************************************************************************/ 
00334 int
00335 dsi_stream_close(dsi_stream_t * stream)
00336 {
00337   int ret;
00338   int error = 0;
00339 
00340   // check stream descriptor
00341   if (!dsi_is_valid_stream(stream))
00342     return -L4_EINVAL;
00343   
00344   // we need at least the close functions for the sockets 
00345   if (stream->sender.close == NULL)
00346     {
00347       LOG_Error("DSI: missing send components close function");
00348       return -L4_EINVAL;
00349     }
00350   if (stream->receiver.close == NULL)
00351     {
00352       LOG_Error("DSI: missing receive components close function");
00353       return -L4_EINVAL;
00354     }
00355 
00356   // stop send component
00357   if (stream->sender.stop != NULL)
00358     {
00359       LOGdL(DEBUG_STREAM,"calling sender (%x) to stop...",
00360             stream->sender.socketref.work_th.id.task);
00361 
00362       ret = stream->sender.stop(&stream->sender);
00363       if (ret)
00364         {
00365           LOG_Error("DSI: stop sender's failed: %s (%d)",
00366                     l4env_errstr(ret),ret);
00367           error = -DSI_ECOMPONENT;
00368         }
00369       LOGdL(DEBUG_STREAM,"sender stop returned");
00370     }
00371 
00372   // stop receive component
00373   if (stream->receiver.stop != NULL)
00374     { 
00375       LOGdL(DEBUG_STREAM,"calling receiver (%x) to stop...",
00376             stream->receiver.socketref.work_th.id.task);
00377 
00378       ret = stream->receiver.stop(&stream->receiver);
00379       if (ret)
00380         {
00381           LOG_Error("DSI: stop receiver's failed: %s (%d)",
00382                     l4env_errstr(ret),ret);
00383           error = -DSI_ECOMPONENT;
00384         }
00385       LOGdL(DEBUG_STREAM,"receiver stop returned");
00386     }
00387 
00388   // close send component 
00389   LOGdL(DEBUG_STREAM,"calling sender (%x) to close...",
00390         stream->sender.socketref.work_th.id.task);
00391 
00392   ret = stream->sender.close(&stream->sender);
00393   if (ret)
00394     {    
00395       LOG_Error("DSI: close sender's socket failed: %s (%d)",
00396                 l4env_errstr(ret),ret);
00397       error = -DSI_ECOMPONENT;
00398     }
00399   LOGdL(DEBUG_STREAM,"sender close returned");
00400 
00401   // close receive component
00402   LOGdL(DEBUG_STREAM,"calling receiver (%x) to close...",
00403         stream->receiver.socketref.work_th.id.task);
00404 
00405   ret = stream->receiver.close(&stream->receiver);
00406   if (ret)
00407     {
00408       LOG_Error("DSI: close receiver's socket failed: %s (%d)",
00409                 l4env_errstr(ret),ret);
00410       error = -DSI_ECOMPONENT;
00411     }
00412   LOGdL(DEBUG_STREAM,"receiver close returned");
00413 
00414   // release stream descriptor 
00415   stream->flags = DSI_STREAM_UNUSED;
00416 
00417   // done 
00418   return error;
00419 }

Generated on Wed Apr 11 06:40:13 2012 for DSI - Drops Streaming Interface by  doxygen 1.5.6