packet.c

Go to the documentation of this file.
00001 /* $Id: packet.c 23143 2005-11-16 21:29:08Z adam $ */
00002 /*****************************************************************************/
00003 /**
00004  * \file   dsi/lib/src/packet.c
00005  * \brief  DROPS Stream Interface. DSI packet handling.
00006  *
00007  * \date   07/01/2000
00008  * \author Lars Reuther <reuther@os.inf.tu-dresden.de>
00009  *
00010  * \note   To avoid the automatic packet numbering, set
00011  *         DO_PACKET_NUMBERING  to 0. The packet number can be set
00012  *         using the dsi_packet_set_no function.
00013  */
00014 /*****************************************************************************/
00015 
00016 /* L4/DROPS includes */
00017 #include <l4/sys/types.h>
00018 #include <l4/sys/syscalls.h>
00019 #include <l4/env/errno.h>
00020 #include <l4/util/atomic.h>
00021 #include <l4/util/macros.h>
00022 #include <l4/thread/thread.h>
00023 
00024 /* library includes */
00025 #include <l4/dsi/dsi.h>
00026 #include "__packet.h"
00027 #include "__sync.h"
00028 #include "__socket.h"
00029 #include "__debug.h"
00030 #include "__config.h"
00031 
00032 /* use automatic packet numbering */
00033 #define DO_PACKET_NUMBERING  0
00034 
00035 /*****************************************************************************
00036  * helpers
00037  *****************************************************************************/
00038 
00039 /*****************************************************************************/
00040 /**
00041  * \brief Check if packet points to a valid packet descriptor of socket.
00042  * \ingroup internal
00043  * 
00044  * \param socket         Socket descriptor
00045  * \param packet         Packet descriptor
00046  *
00047  * \return 1 if \a packet is a valid packet descriptor, 0 otherwise 
00048  */
00049 /*****************************************************************************/ 
00050 static inline int
00051 __is_valid_packet(dsi_socket_t * socket, dsi_packet_t * packet)
00052 {
00053   return ((packet >= socket->packets) && 
00054           ((l4_addr_t)packet < 
00055            ((l4_addr_t)socket->packets + 
00056             socket->header->num_packets * sizeof(dsi_packet_t))));
00057 }
00058 
00059 
00060 #define set_socket_flag(s, f)           \
00061     __asm__ __volatile__ (              \
00062         "orl    %1,%0   \n\t"           \
00063         :                               \
00064         :"m" ((s)->flags), "g" (f)      \
00065         :"memory"                       \
00066         )
00067 
00068 #define reset_socket_flag(s, f)         \
00069     __asm__ __volatile__ (              \
00070         "andl   %1,%0   \n\t"           \
00071         :                               \
00072         :"m" ((s)->flags), "g" (~f)     \
00073         :"memory"                       \
00074         )
00075 
00076 
00077 /*****************************************************************************/
00078 /**
00079  * \brief Calculate packet index.
00080  * \ingroup internal
00081  * 
00082  * \param socket         Socket descriptor
00083  * \param packet         Packet descriptor
00084  *
00085  * \return index of packet in packet array
00086  *
00087  * \note No sanity checks!
00088  */
00089 /*****************************************************************************/ 
00090 static inline int
00091 __get_packet_index(dsi_socket_t * socket, dsi_packet_t * packet)
00092 {
00093   return (int)(((l4_addr_t)packet - (l4_addr_t)socket->packets) / 
00094                sizeof(dsi_packet_t));
00095 }
00096 
00097 /*****************************************************************************/
00098 /**
00099  * \brief Send release packet notification to send component.
00100  * \ingroup internal
00101  * 
00102  * \param socket         Socket descriptor
00103  * \param packet         Packet descriptor
00104  *
00105  * \return 0 on success (notification sent), error code otherwise:
00106  *         - -L4_EIPC IPC error calling send components sync thread
00107  */
00108 /*****************************************************************************/ 
00109 static inline int
00110 __send_release_notification(dsi_socket_t * socket, dsi_packet_t * packet)
00111 {
00112   int ret;
00113   l4_msgdope_t result;
00114   l4_uint32_t p;
00115 #if RELEASE_DO_CALL
00116   l4_umword_t dummy;
00117 #endif
00118 
00119   LOGdL(DEBUG_RECEIVE_PACKET,"packet %d",packet->no);
00120   LOGdL(DEBUG_RECEIVE_PACKET,"remote sync "l4util_idfmt,
00121         l4util_idstr(socket->remote_socket.sync_th));
00122   
00123   /* get packet index */
00124   p = __get_packet_index(socket,packet);
00125 
00126   /* send notification message */
00127   do
00128     {
00129       /* call send component */
00130 #if RELEASE_DO_CALL
00131       ret = l4_ipc_call(socket->remote_socket.sync_th,L4_IPC_SHORT_MSG,
00132                              DSI_SYNC_RELEASE,p,L4_IPC_SHORT_MSG,&dummy,
00133                              &dummy,L4_IPC_NEVER,&result);
00134 #else
00135       ret = l4_ipc_send(socket->remote_socket.sync_th,L4_IPC_SHORT_MSG,
00136                              DSI_SYNC_RELEASE,p,L4_IPC_NEVER,&result);
00137 #endif
00138 
00139       if (ret == L4_IPC_SETIMEOUT)
00140         {
00141 #if 0
00142           LOG_Error("DSI: send timeout calling sender, ignored.");
00143 #endif
00144           l4thread_sleep(1);
00145         }
00146     }
00147   while (ret == L4_IPC_SETIMEOUT);
00148 
00149   if (ret)
00150     {
00151       LOG_Error("DSI: error sending release notification (0x%02x)!", ret);
00152       return -L4_EIPC;
00153     }
00154 
00155   /* done */
00156   return 0;
00157 }
00158 
00159 /*****************************************************************************/
00160 /**
00161  * \brief Find unused scatter gather list element.
00162  * \ingroup internal
00163  * 
00164  * \param  socket        Socket descriptor.
00165  * \retval sg_elem       Index of empty scattet gather list element
00166  *
00167  * \retval 0            got unused element, \c sg_elem contains index to
00168  *                      empty scatter-gather list element
00169  * \retval -DSI_ENOSGELEM no scatter-gather list element found
00170  *
00171  * Unused packets have data address set to 0xFFFFFFFF.
00172  */
00173 /*****************************************************************************/ 
00174 static inline int
00175 __get_sg_elem(dsi_socket_t * socket, int * sg_elem)
00176 {
00177   int i = socket->next_sg_elem;
00178 
00179   *sg_elem = -1;
00180 
00181   /* search packet */
00182   do
00183     {
00184       if (l4util_cmpxchg32(&socket->sg_lists[i].flags,
00185                            DSI_SG_ELEM_UNUSED,DSI_SG_ELEM_USED))
00186         {
00187           /* found */
00188           socket->next_sg_elem = (i + 1) % socket->header->num_sg_elems;
00189           break;
00190         }
00191 
00192       i = (i + 1) % socket->header->num_sg_elems;
00193     }
00194   while (i != socket->next_sg_elem);
00195 
00196   if (i == socket->next_sg_elem)
00197     {
00198       /* this should never happen */
00199       Panic("DSI: no scatter gather list element available!");
00200       return -DSI_ENOSGELEM;
00201     }
00202   else
00203     {
00204       *sg_elem = i;
00205       return 0;
00206     }
00207 }
00208 
00209 /*****************************************************************************/
00210 /**
00211  * \brief Try to lock next send packet in packet ring list.
00212  * \ingroup internal
00213  * 
00214  * \param  socket        Socket descriptor
00215  * \retval packet        Index of next send packet
00216  *
00217  * \retval 0                    on success (\a packet contains valid index)
00218  * \retval -DSI_ENOPACKET       - non-blocking mode: next packet still used
00219  *                                by the receive component
00220  *                              - blocking mode: block/unblock-ipc returned
00221  *                                an error
00222  * \retval -DSI_ECONNECT        blocking mode: communication peer does
00223  *                              not exist
00224  *
00225  * If the packet is still used by the receiver, either block and wait until
00226  * it is released (if DSI_SOCKET_BLOCK flag is set in socket descriptor) or
00227  * return an error otherwise.
00228  */
00229 /*****************************************************************************/ 
00230 static inline int
00231 __get_send_packet(dsi_socket_t * socket, int * packet)
00232 {
00233   dsi_sync_msg_t msg;
00234   dsi_packet_t * p = &socket->packets[socket->next_packet];
00235   int err;
00236   
00237   LOGdL(DEBUG_SEND_PACKET,"trying to get packet %d",socket->next_packet);
00238 
00239   /* Abort-Flag set in between? */
00240   if(socket->flags & DSI_SOCKET_BLOCK_ABORT) goto e_eeos;
00241   if (!dsi_trylock(&p->tx_sem)){
00242     /* We did not get the packet. This is not the normal case. */
00243     if (SOCKET_BLOCK(socket)) {
00244       /* Blocking socket. Prepare for waiting. Our peer will not
00245          see that we block until we are inside dsi_down(). This
00246          means, the preparation might be for nothing, and that our
00247          threads must not count on our blocking only because it
00248          sees the sync_callback or the DSI_SOCKET_BLOCKING_IN_GET
00249          flag set. */
00250 
00251       if(l4_thread_setjmp(socket->packet_get_abort_env)) goto e_eeos;
00252 
00253       /* Tell our threads we are blocking */
00254       set_socket_flag(socket, DSI_SOCKET_BLOCKING_IN_GET);
00255 
00256       /* After(!) setting the blocking flag, check again if we should
00257          abort. */
00258       if(socket->flags & DSI_SOCKET_BLOCK_ABORT) goto e_eeos;
00259 
00260       if (SOCKET_SYNC_CALLBACK(socket)){
00261         /* packet not available, call synchronization callback */
00262         socket->sync_callback(socket,socket->packet_count,
00263                               DSI_SYNC_NO_SEND_PACKET);
00264       }
00265 
00266       /* block now */
00267       msg.sync_th = socket->remote_socket.sync_th;
00268       msg.packet = socket->next_packet;
00269       msg.rcv = L4_IPC_SHORT_MSG;
00270       err = dsi_down(&p->tx_sem,msg);
00271 
00272       /* Not waiting anymore */
00273       reset_socket_flag(socket, DSI_SOCKET_BLOCKING_IN_GET);
00274 
00275       if(err!=-1 && err){
00276         return ((err & L4_IPC_ERROR_MASK) == L4_IPC_ENOT_EXISTENT)?
00277           -DSI_ECONNECT:-DSI_ENOPACKET;
00278       }
00279     }
00280     else {
00281       /* Most unusual case: nonblocking socket which does not get a
00282          packet. */
00283       return -DSI_ENOPACKET;
00284     }
00285   }
00286 
00287   /* got the packet */
00288   *packet = socket->next_packet;
00289   socket->next_packet = 
00290     (socket->next_packet + 1) % socket->header->num_packets;
00291 
00292   /* setup packet descriptor */
00293 #if DO_PACKET_NUMBERING
00294   p->no = socket->packet_count++;
00295 #endif
00296   p->flags &= (~DSI_PACKETS_USER_MASK);
00297   p->sg_len = 0;
00298   p->sg_list = DSI_SG_ELEM_LAST;
00299 
00300   return 0;
00301 
00302  e_eeos:
00303   reset_socket_flag(socket,
00304                     DSI_SOCKET_BLOCKING_IN_GET |
00305                     DSI_SOCKET_BLOCK_ABORT);
00306   return -DSI_EEOS;
00307 }
00308 
00309 
00310 /*****************************************************************************/
00311 /**
00312  * \brief Map packet data.
00313  * 
00314  * \param socket         Socket descriptor
00315  * \param packet_idx     Packet index
00316  *
00317  * Call send component to map packet data.
00318  */
00319 /*****************************************************************************/ 
00320 static inline void
00321 __map_receive_data(dsi_socket_t * socket, int packet_idx)
00322 {
00323   int ret;
00324   l4_umword_t dummy;
00325   l4_msgdope_t result;
00326 
00327   LOGdL(DEBUG_MAP_PACKET,"map packet %d",packet_idx);
00328 
00329   /* call send dync thread */
00330   ret = l4_ipc_call(socket->remote_socket.sync_th,
00331                          L4_IPC_SHORT_MSG,DSI_SYNC_MAP,packet_idx,
00332                          L4_IPC_MAPMSG((l4_addr_t)socket->data_area,
00333                                        socket->data_map_size),
00334                          &dummy,&dummy,L4_IPC_NEVER,&result);
00335   if (ret || !l4_ipc_fpage_received(result))
00336     Panic("DSI: map message IPC error (0x%08x)!",ret);
00337 }
00338 
00339 /*****************************************************************************/
00340 /**
00341  * \brief Copy packet data.
00342  * 
00343  * \param socket         Socket descriptor
00344  * \param packet_idx     Packet index   
00345  *
00346  * Call send component to copy packet data.
00347  */
00348 /*****************************************************************************/ 
00349 static inline void 
00350 __copy_receive_data(dsi_socket_t * socket, int packet_idx)
00351 {
00352   int ret;
00353   struct {
00354     l4_umword_t      rcv_fpage;
00355     l4_msgdope_t size_dope;
00356     l4_msgdope_t send_dope;
00357     l4_umword_t      dw0;
00358     l4_umword_t      dw1;
00359     l4_strdope_t buf;
00360   } msg_buf;
00361   l4_umword_t dummy;
00362   l4_msgdope_t result;
00363 
00364   LOGdL(DEBUG_COPY_PACKET,"copy packet %d",packet_idx);
00365 
00366   /* call send sync thread */
00367   msg_buf.rcv_fpage = 0;
00368   msg_buf.size_dope = L4_IPC_DOPE(2,1);
00369   msg_buf.send_dope = L4_IPC_DOPE(2,0);
00370   msg_buf.buf.rcv_str = (l4_addr_t)socket->data_area;
00371   msg_buf.buf.rcv_size = socket->data_size;
00372  
00373   ret = l4_ipc_call(socket->remote_socket.sync_th,
00374                          L4_IPC_SHORT_MSG,DSI_SYNC_COPY,packet_idx,
00375                          &msg_buf,&dummy,&dummy,L4_IPC_NEVER,&result);
00376   if (ret || (result.md.strings != 1))
00377     Panic("DSI: copy message IPC error (0x%08x)!",ret);                  
00378 }
00379 
00380 /*****************************************************************************/
00381 /**
00382  * \brief Try to lock next receive packet in packet ring list.
00383  * \ingroup internal
00384  * 
00385  * \param  socket        Socket descriptor
00386  * \retval packet        Index of next receive packet
00387  *
00388  * \retval 0                    on success (\a packet contains valid index)
00389  * \retval -DSI_ENOPACKET       - non-blocking mode: next packet still used
00390  *                                by the send component
00391  *                              - blocking mode: block/unblock-ipc returned
00392  *                                an error
00393  * \retval -DSI_EEOS            aborted by dsi_packet_get_abort()
00394  * \retval -DSI_ECONNECT        blocking mode: communication peer does
00395  *                              not exist
00396  *
00397  * If the packet is not available yet (sender didn't commit data), either
00398  * block and wait until sender commited data (if DSI_SOCKET_BLOCK flag is
00399  * set in socket descriptor) or return an error otherwise.
00400  *
00401  * There are two ways to map/copy the data of a packet (required if 
00402  * DSI_SOCKET_MAP or DSI_SOCKET_COPY flags are set for the socket). If 
00403  * \a dsi_down calls the sender sync thread to wait for the next packet,
00404  * the sender maps/copies the data in the reply message 
00405  * (see dsi_sync_thread_send()). If we get the packet without calling 
00406  * the remote sync thread, we must map/copy the data explicitly.
00407  */
00408 /*****************************************************************************/ 
00409 static inline int 
00410 __get_receive_packet(dsi_socket_t * socket, int * packet)
00411 {
00412   dsi_sync_msg_t msg;
00413   int result = -1;
00414   l4_msgdope_t dope;
00415   struct {
00416     l4_umword_t      rcv_fpage;
00417     l4_msgdope_t size_dope;
00418     l4_msgdope_t send_dope;
00419     l4_umword_t      dw0;
00420     l4_umword_t      dw1;
00421     l4_strdope_t buf;
00422   } msg_buf;
00423 
00424   LOGdL(DEBUG_RECEIVE_PACKET,"trying to get packet %d",socket->next_packet);
00425 
00426   /* Abort-Flag set in between? */
00427   if(socket->flags & DSI_SOCKET_BLOCK_ABORT) goto e_eeos;
00428   if(!dsi_trylock(&socket->packets[socket->next_packet].rx_sem)){
00429     if (SOCKET_BLOCK(socket)) {
00430       /* Blocking socket. Prepare for waiting */
00431 
00432       /* Setup synchronization message */
00433       msg.sync_th = socket->remote_socket.sync_th;
00434       msg.packet = socket->next_packet;
00435       if (socket->flags & DSI_SOCKET_MAP) 
00436         {
00437           /* set receive descriptor to receive fpage */
00438           msg.rcv = L4_IPC_MAPMSG((l4_addr_t)socket->data_area,
00439                                   socket->data_map_size);
00440 
00441           LOGdL(DEBUG_MAP_PACKET,"rcv fpage 0x%08x",(unsigned)msg.rcv);
00442         } 
00443       else if (socket->flags & DSI_SOCKET_COPY) 
00444         {
00445           /* set receive descriptor to copy message */
00446           msg_buf.rcv_fpage = 0;
00447           msg_buf.size_dope = L4_IPC_DOPE(2,1);
00448           msg_buf.send_dope = L4_IPC_DOPE(2,0);
00449           msg_buf.buf.rcv_str = (l4_addr_t)socket->data_area;
00450           msg_buf.buf.rcv_size = socket->data_size;
00451 
00452           LOGdL(DEBUG_COPY_PACKET,"rcv str at 0x%08lx",msg_buf.buf.rcv_str);
00453           LOGdL(DEBUG_COPY_PACKET,"size %u",socket->data_size);
00454 
00455           msg.rcv = &msg_buf;
00456         } 
00457       else
00458         msg.rcv = L4_IPC_SHORT_MSG;
00459 
00460       if(l4_thread_setjmp(socket->packet_get_abort_env)) goto e_eeos;
00461 
00462       /* Tell our threads we are blocking */
00463       set_socket_flag(socket, DSI_SOCKET_BLOCKING_IN_GET);
00464 
00465       /* After(!) setting the blocking flag, check again if we should
00466          abort. */
00467       if(socket->flags & DSI_SOCKET_BLOCK_ABORT) goto e_eeos;
00468 
00469       if (SOCKET_SYNC_CALLBACK(socket)) {
00470         socket->sync_callback(socket,
00471                               socket->packets[socket->next_packet].no,
00472                               DSI_SYNC_NO_RECEIVE_PACKET);
00473       }
00474 
00475       /* block */
00476       result = dsi_down(&socket->packets[socket->next_packet].rx_sem,msg);
00477 
00478       /* Not waiting anymore */
00479       reset_socket_flag(socket, DSI_SOCKET_BLOCKING_IN_GET);
00480 
00481       if(result!=-1 && result)
00482         return ((result & L4_IPC_ERROR_MASK)==L4_IPC_ENOT_EXISTENT)?
00483           -DSI_ECONNECT:-DSI_ENOPACKET;
00484 
00485     }   else {
00486       /* Most unusual case: nonblocking socket which does not get a
00487          packet. */
00488       return -DSI_ENOPACKET;
00489     }
00490   } /* got the packet */
00491       
00492   LOGdL(DEBUG_RECEIVE_PACKET,"got packet %d",socket->next_packet);
00493 
00494   /* got the packet */
00495   *packet = socket->next_packet;
00496 
00497   socket->next_packet = 
00498     (socket->next_packet + 1) % socket->header->num_packets;
00499 
00500   /* check if we need to map/copy packet data */
00501   if (socket->flags & DSI_SOCKET_MAP)
00502     {
00503       if (result == -1)
00504         /* no call to sync thread, map packet data */
00505         __map_receive_data(socket,*packet);
00506       else
00507         {
00508           /* check result dope */
00509           dope.msgdope = result;
00510           if (!dope.md.fpage_received)
00511             {
00512               LOG_Error("DSI: packet data not mapped!");
00513               __map_receive_data(socket,*packet);
00514             }
00515         }
00516     }
00517   else if (socket->flags & DSI_SOCKET_COPY)
00518     {
00519       if (result == -1)
00520         /* no call to sync thread, copy packet data */
00521         __copy_receive_data(socket,*packet);
00522       else
00523         {
00524           /* check result dope */
00525           dope.msgdope = result;
00526           if (dope.md.strings != 1)
00527             {
00528               LOG_Error("DSI: packet data not copied!");
00529               __copy_receive_data(socket,*packet);
00530             }
00531         }
00532     }
00533 
00534   /* done */
00535   return 0;
00536 
00537  e_eeos:
00538   reset_socket_flag(socket,
00539                     DSI_SOCKET_BLOCKING_IN_GET |
00540                     DSI_SOCKET_BLOCK_ABORT);
00541   return -DSI_EEOS;
00542 }
00543 
00544 /*****************************************************************************/
00545 /**
00546  * \brief Commit send packet.
00547  * \ingroup internal
00548  * 
00549  * \param  socket        Socket descriptor
00550  * \param  packet        Packet descriptor
00551  *
00552  * \return 0 on success, error code otherwise
00553  *         - -L4_EINVAL     invalid packet descriptor
00554  *         - -DSI_ENODATA   tried to commit empty packet
00555  *         - -DSI_ENOPACKET peer in blocking mode: committing required a
00556  *                          sync-message which failed
00557  *
00558  * The receiver can now use this packet. If the receiver is already waiting
00559  * for this packet, send wakup message to our synchronization thread.
00560  */
00561 /*****************************************************************************/ 
00562 static inline int
00563 __commit_send_packet(dsi_socket_t * socket, dsi_packet_t * packet)
00564 { 
00565   dsi_sync_msg_t msg;
00566 
00567 #if DO_SANITY
00568   /* check packet descriptor */
00569   if (!__is_valid_packet(socket,packet))
00570     return -L4_EINVAL;
00571 #endif
00572 
00573   if (packet->sg_len == 0)
00574     return -DSI_ENODATA;
00575 
00576   /* set packet flags */
00577   if (SOCKET_RELEASE_CALLBACK(socket))
00578     packet->flags |= DSI_PACKET_RELEASE_CALLBACK;
00579 
00580   /* we possibly need to wakup receiver, setup synchronization message */
00581   msg.sync_th = socket->sync_th; /* the receiver is waiting for our sync thread */
00582   msg.packet = __get_packet_index(socket,packet);
00583 
00584   LOGdL(DEBUG_SEND_PACKET,"commiting packet %d",msg.packet);
00585   LOGdL(DEBUG_SEND_PACKET,"message to "l4util_idfmt,
00586         l4util_idstr(msg.sync_th));
00587 
00588   socket->header->packets_committed++;
00589 
00590   /* commit packet, the rx_sem counter of the packet is used to synchronize 
00591    * valid send data (see __get_receive_packet) */
00592   if(dsi_up(&packet->rx_sem,msg)) 
00593     return -DSI_ENOPACKET;
00594 
00595   /* done */
00596   return 0;
00597 }
00598 
00599 /*****************************************************************************/
00600 /**
00601  * \brief Commit (release) received packet.
00602  * \ingroup internal
00603  *
00604  * \param socket                socket descriptor
00605  * \param packet                packet to commit
00606  *
00607  * \retval 0                    success
00608  * \retval -L4_EINVAL           invalid packet descriptor
00609  * \retval -L4_EIPC             IPC error sending release notifcation to
00610  *                              sender
00611  * \retval -DSI_ENOPACKET       peer in blocking mode: IPC error sending
00612  *                              unblock-notification
00613  *
00614  * The send component can now use this packet for the next send packet. If
00615  * the sender is already waiting for the packet, send wakeup message.
00616  */
00617 /*****************************************************************************/ 
00618 static inline int
00619 __commit_receive_packet(dsi_socket_t * socket, dsi_packet_t * packet)
00620 {
00621   dsi_sync_msg_t msg;
00622   int i,j,sg_elem,a;
00623   int ret = 0;
00624   int do_unmap = socket->flags & DSI_SOCKET_MAP;
00625   void *addr = socket->data_area;
00626 
00627 #if DO_SANITY
00628   /* check packet descriptor */
00629   if (!__is_valid_packet(socket,packet))
00630     return -L4_EINVAL;
00631 #endif
00632 
00633   /* reset get index so that the sender can use dsi_packet_get_data to read 
00634    * the data areas */
00635   packet->sg_idx = packet->sg_list;
00636 
00637   /* unmap packet data, we must do this before we send the release callback */
00638   if (do_unmap)
00639     {
00640       sg_elem = packet->sg_list;
00641       while (sg_elem != DSI_SG_ELEM_LAST)
00642         {
00643           /* unmap packet data */
00644           LOGdL(DEBUG_MAP_PACKET,"unmap packet %u",packet->no);
00645 
00646           a = 12;
00647           while (socket->sg_lists[sg_elem].size > (1U << a))
00648             a++;
00649 
00650           /* unmap */
00651           l4_fpage_unmap(l4_fpage((l4_addr_t)addr + 
00652                                   socket->sg_lists[sg_elem].addr,
00653                                   a,0,0),
00654                          L4_FP_FLUSH_PAGE | L4_FP_ALL_SPACES);
00655 
00656           sg_elem = socket->sg_lists[sg_elem].next;
00657         }
00658     }
00659 
00660   /* check if we should send release notification to send component */
00661   if (PACKET_RELEASE_CALLBACK(packet))
00662     /* send release notification */
00663     ret = __send_release_notification(socket,packet);
00664 
00665   /* we possibly need to wakup the sender, setup synchronization message */
00666   msg.sync_th = socket->sync_th; /* the sender is waiting for our sync thread */
00667   msg.packet = __get_packet_index(socket,packet);
00668 
00669   socket->header->packets_committed--;
00670   
00671   /* release scatter gather list elements */
00672   sg_elem = packet->sg_list;
00673   for (i = 0; i < packet->sg_len; i++)
00674     {
00675       if (sg_elem == DSI_SG_ELEM_LAST)
00676         {
00677           Panic("DSI: corrupted sgatter gather list");
00678           return -L4_EINVAL;
00679         }
00680 
00681       j = sg_elem;
00682       sg_elem = socket->sg_lists[j].next;
00683       socket->sg_lists[j].flags = DSI_SG_ELEM_UNUSED;
00684     }
00685 
00686   if (sg_elem != DSI_SG_ELEM_LAST)
00687     {
00688       Panic("DSI: corrupted sgatter gather list");
00689       return -L4_EINVAL;
00690     }
00691 
00692   /* release packet, the tx_sem counter of the packet is used to synchronize 
00693    * the free packets (see __get_send_packet) */
00694   if(dsi_up(&packet->tx_sem,msg)) return -DSI_ENOPACKET;
00695 
00696   /* done */
00697   return ret;
00698 }
00699 
00700 /*****************************************************************************
00701  * API functions
00702  *****************************************************************************/
00703 
00704 /*****************************************************************************/
00705 /**
00706  * \brief Request next send/receive packet.
00707  * \ingroup packet
00708  * 
00709  * \param  socket        Socket descriptor
00710  * \retval packet        Pointer to next packet
00711  * 
00712  * \retval 0                    on success (\a packet contains valid index)
00713  * \retval -DSI_ENOPACKET       non-blocking mode: next packet still used
00714  *                              by the receive component
00715  * \retval -DSI_ENOPACKET       blocking mode: block/unblock-ipc returned
00716  *                              an error
00717  * \retval -DSI_EEOS            aborted by dsi_packet_get_abort()
00718  * \retval -DSI_ECONNECT        blocking mode: communication peer does
00719  *                              not exist
00720  */
00721 /*****************************************************************************/ 
00722 int 
00723 dsi_packet_get(dsi_socket_t * socket, dsi_packet_t ** packet)
00724 {
00725   int ret,i;
00726 
00727 #if DO_SANITY
00728   /* check socket descriptor */
00729   if (!dsi_is_valid_socket(socket))
00730     return -L4_EINVAL;
00731 #endif
00732 
00733   /* get next send/receive packet */
00734   if (IS_SEND_SOCKET(socket))
00735     ret = __get_send_packet(socket,&i);
00736   else if (IS_RECEIVE_SOCKET(socket))
00737     ret = __get_receive_packet(socket,&i);
00738   else
00739     {
00740       Panic("DSI: invalid socket");
00741       return -L4_EINVAL;
00742     }
00743 
00744   if (ret && (ret != -DSI_ENOPACKET) && ret!=-DSI_EEOS)
00745     {
00746       LOG_Error("DSI: get packet failed: %s (%d)\n", l4env_errstr(ret), ret);
00747       return ret;
00748     }
00749 
00750   if (ret) return ret;
00751   
00752 #if (DEBUG_SEND_PACKET || DEBUG_RECEIVE_PACKET)
00753   LOGL("got packet %d",i);
00754 #endif
00755 
00756   /* setup packet descriptor */
00757   *packet = &socket->packets[i];
00758   if (IS_SEND_SOCKET(socket))
00759     (*packet)->sg_idx = DSI_SG_ELEM_LAST;
00760   else
00761     (*packet)->sg_idx = (*packet)->sg_list;
00762 
00763   /* done */
00764   return 0;
00765 }
00766 
00767 /*****************************************************************************/
00768 /**
00769  * \brief Abort an ongoing packet_get() in the work-thread.
00770  *
00771  * \ingroup packet
00772  * 
00773  * \param  socket        Socket descriptor
00774  * 
00775  * \retval 0 on success         (\a packet_get was ongoing), error otherwise
00776  * \retval -DSI_ENOPACKET       the work-thread was not blocking inside
00777  *                              a packet_get. The next dsi_packet_get() will
00778  *                              return -DSI_EEOS
00779  * \retval -DSI_EINVAL          invalid socket descriptor
00780  *
00781  * This function can be used to abort a dsi_packet_get(), which was
00782  * issued by the work-thread of the socket. After the abort, the
00783  * socket is in an undefined state regarding the packet list. This
00784  * means, further calls to dsi_packet_get() deliver undefined results.
00785  * The same hold for the communication peer.
00786  *
00787  * The intended use of this function is to unblock the worker if the socket
00788  * should be shut down by an service thread.
00789  *
00790  * \note This function must not be called if the dsi_packet_get() was not
00791  *       issued by the work-thread of the socket.
00792  *
00793  * \note This function must not called more than once per socket.
00794  *
00795  */
00796 /****************************************************************************/ 
00797 int 
00798 dsi_packet_get_abort(dsi_socket_t * socket)
00799 {
00800 #if DO_SANITY
00801   /* check socket descriptor */
00802   if (!dsi_is_valid_socket(socket))
00803     return -L4_EINVAL;
00804 #endif
00805 
00806   set_socket_flag(socket, DSI_SOCKET_BLOCK_ABORT);
00807 
00808   if(socket->flags & DSI_SOCKET_BLOCKING_IN_GET){
00809     /* it is actually inside a packet get. The longjmp-environment is
00810      * therefore valid. ex-regs the thread to the longjump-function. */
00811     l4_thread_longjmp(socket->work_th, socket->packet_get_abort_env, 1);
00812     return 0;
00813   }
00814 
00815   return -DSI_ENOPACKET;
00816 }
00817 
00818 
00819 /*****************************************************************************/
00820 /**
00821  * \brief Wait for specific packet.
00822  * \ingroup packet
00823  *
00824  * \param  socket        Socket descriptor
00825  * \param  packet        Packet descriptor
00826  * 
00827  * \retval 0                    success (\a packet contains valid packet)
00828  * \retval -DSI_ENOPACKET       - non-blocking mode: next packet still used
00829  *                                by the receive component
00830  *                              - blocking mode: block/unblock-ipc returned
00831  *                                an error
00832  * \retval -DSI_ENODATA         tried to commit empty send packet
00833  *
00834  * \Todo   Implemented dsi_packet_get_nr().
00835  *
00836  * This function requests a packet with a given sequence number. It should be
00837  * used together with unblocking synchronisation.
00838  *
00839  * \note   The range of sequence numbers is limited, resulting in a wraparound
00840  *         sometimes. When calculating the packet number directly using
00841  *         the remainder of a division, we end up in having steps in our
00842  *         sequence.
00843  *         Thus we have a window of valid framenumbers represented by 
00844  *         a number limited in size, out of an inifinite range of framenumbers.
00845  *         This also requires an additional offset that is added prior
00846  *         to packet-place calculation out of the packet nr. But, we will deal
00847  *         with this later. For now, it is sufficient to have 32bit-IDs, this
00848  *         lasts for about 50days with 1kHz framerate.
00849  */
00850 /*****************************************************************************/ 
00851 int 
00852 dsi_packet_get_nr(dsi_socket_t * socket, unsigned nr, dsi_packet_t ** packet)
00853 {
00854   /* not implemented yet */
00855   return 0;
00856 }
00857 
00858 /*****************************************************************************/ 
00859 /**
00860  * \brief Commit send / release receive packet.
00861  * \ingroup packet
00862  *
00863  * \param socket        socket descriptor
00864  * \param packet        packet to commit
00865  *
00866  * \retval 0              success
00867  * \retval -L4_EINVAL  invalid socket/packet descriptor
00868  * \retval -DSI_ENODATA   tried to commit empty send packet
00869  * \retval -DSI_ENOPACKET peer in blocking mode: committing required a
00870  *                        sync-message which failed
00871  */
00872 /*****************************************************************************/ 
00873 int
00874 dsi_packet_commit(dsi_socket_t * socket, dsi_packet_t * packet)
00875 {
00876   int ret;
00877 
00878 #if DO_SANITY
00879   /* check socket descriptor */
00880   if (!dsi_is_valid_socket(socket))
00881     return -L4_EINVAL;
00882 #endif
00883 
00884   /* commit send/recveive packet */
00885   if (IS_SEND_SOCKET(socket))
00886     ret = __commit_send_packet(socket,packet);
00887   else if (IS_RECEIVE_SOCKET(socket))
00888     ret = __commit_receive_packet(socket,packet);
00889   else
00890     {
00891       LOG_Error("DSI: invalid socket");
00892       return -L4_EINVAL;
00893     }
00894   
00895   if (ret)
00896     {
00897       LOG_Error("DSI: commit packet failed: %s (%d)", l4env_errstr(ret), ret);
00898       return ret;
00899     }
00900 
00901   /* done */
00902   return 0;
00903 }
00904 
00905 /*****************************************************************************/
00906 /**
00907  * \brief Add data area to packet's scatter gather list.
00908  * \ingroup packet
00909  * 
00910  * \param socket         Socket descriptor
00911  * \param packet         Packet descriptor
00912  * \param addr           data start address
00913  * \param size           data size
00914  * \param flags          data area flags, can be a combination of
00915  *                       -# DSI_DATA_AREA_GAP to add a gap, address ignored
00916  *                       -# DSI_DATA_AREA_EOS to signal the end of stream,
00917  *                          address and size are ignored
00918  *                       -# DSI_DATA_AREA_PHYS to add a packet whose physical
00919  *                          address is given in addr
00920  * 
00921  * \return 0 on success, error code otherwise:
00922  *         - -L4_EINVAL  invalid socket/packet/data area
00923  *         - -DSI_ESGLIST   scatter gather list too long
00924  *         - -DSI_ENOSGELEM no scatter gather element available
00925  */
00926 /*****************************************************************************/ 
00927 int 
00928 dsi_packet_add_data(dsi_socket_t * socket, dsi_packet_t * packet, 
00929                     void * addr, l4_size_t size,
00930                     l4_uint32_t flags)
00931 {
00932   l4_addr_t offs;
00933   int ret,sg_elem;
00934 
00935 #if DO_SANITY
00936   /* check socket */
00937   if (!dsi_is_valid_socket(socket))
00938     return -L4_EINVAL;
00939 
00940   /* check packet */
00941   if (!__is_valid_packet(socket,packet))
00942     return -L4_EINVAL;
00943 
00944   /* only send components can add data */
00945   if (!IS_SEND_SOCKET(socket))
00946     return -L4_EINVAL;
00947 #endif
00948 
00949   /* check scatter gather list */
00950   if (packet->sg_len >= socket->header->max_sg_len)
00951     {
00952       /* exceeded max scatter gather list length */
00953       LOG_Error("DSI: scatter gather list too long (%d)", packet->sg_len + 1);
00954       return -DSI_ESGLIST;
00955     }
00956 
00957   /* calculate address offset, the scatter gather list elements stor the 
00958    * offset relative to the start of the data area */
00959   if (!(flags & DSI_DATA_AREA_GAP) && 
00960       !(flags & DSI_DATA_AREA_EOS) &&
00961       !(flags & DSI_DATA_AREA_PHYS))
00962     {
00963       /* data area contains valid data, really check offset/size */ 
00964       offs = addr - socket->data_area;
00965       if ((offs > socket->data_size) || 
00966           ((offs + size) > socket->data_size) ||
00967           (size == 0))
00968         {
00969           /* invalid data area */
00970           LOG_Error ("DSI: invalid data area (addr 0x%08lx, size %u)",
00971                      (l4_addr_t)addr, size);
00972           return -L4_EINVAL;
00973         }
00974     }
00975   else if(flags & DSI_DATA_AREA_PHYS) {
00976     offs = (l4_addr_t)addr;
00977   } else
00978     /* data area contains no data */
00979     offs = 0;
00980 
00981   /* add scatter gather list element */
00982   ret = __get_sg_elem(socket,&sg_elem);
00983   if (ret)
00984     return -DSI_ENOSGELEM;
00985 
00986   socket->sg_lists[sg_elem].addr = offs;
00987   socket->sg_lists[sg_elem].size = size;
00988   socket->sg_lists[sg_elem].flags |= (flags & DSI_SG_ELEM_USER_MASK);
00989   socket->sg_lists[sg_elem].next = DSI_SG_ELEM_LAST;
00990 
00991   if (packet->sg_len == 0)
00992     {
00993       /* add first element in scatter gather list */
00994       packet->sg_list = sg_elem;
00995       packet->sg_idx = sg_elem;
00996       packet->sg_len = 1;
00997     }
00998   else
00999     {
01000       /* add element at the end of the list */
01001       socket->sg_lists[packet->sg_idx].next = sg_elem;
01002       packet->sg_idx = sg_elem;
01003       packet->sg_len++;
01004     }
01005 
01006   /* done */
01007   return 0;
01008 }
01009 
01010 /*****************************************************************************/
01011 /**
01012  * \brief Get next data area from packet.
01013  * \ingroup packet
01014  * 
01015  * \param  socket        Socket descriptor
01016  * \param  packet        Packet descriptor
01017  * \retval addr          Start address (absolute) of data area
01018  * \retval size          Size of data area
01019  * 
01020  * \return 0 on success (\a addr and \a size describe a valid data area), 
01021  *         error code otherwise:
01022  *         - -DSI_EPHYS    chunk describes a piece of physical memory.
01023  *                         addr contains the physical address of the data.
01024  *         - -DSI_EGAP     chunk describes gap in stream, size is the size
01025  *                         of the gap
01026  *         - -DSI_EEOS     packet signals the end of the stream
01027  *         - -DSI_ENODATA  packet contains no more data
01028  *         - -L4_EINVAL    invalid socket or packet descriptor
01029  * 
01030  * Get next data area from packet. If the packet contains more than one
01031  * area, get_data returns the next area in the scatter gather list and
01032  * dsi_packet_get_data must be called repeatedly to get the rest of the
01033  * scatter gather list.
01034  */
01035 /*****************************************************************************/ 
01036 int 
01037 dsi_packet_get_data(dsi_socket_t * socket, dsi_packet_t * packet,
01038                     void **addr, l4_size_t * size)
01039 {
01040   l4_uint32_t nr;
01041 
01042 #if DO_SANITY
01043   /* check socket */
01044   if (!dsi_is_valid_socket(socket))
01045     return -L4_EINVAL;
01046 
01047   /* check packet */
01048   if (!__is_valid_packet(socket,packet))
01049     return -L4_EINVAL;
01050 #endif
01051 
01052   nr = packet->sg_idx;  /* prevent our peer from chaning the index while
01053                            we are using it */
01054                            
01055   if(nr < socket->num_sg_elems){
01056     l4_uint32_t flags;
01057 
01058     // normal case: we have a valid packet
01059     /* get data */
01060     *size = socket->sg_lists[nr].size;
01061     packet->sg_idx = socket->sg_lists[nr].next;
01062         
01063     flags = socket->sg_lists[nr].flags & (DSI_DATA_AREA_GAP |
01064                                           DSI_DATA_AREA_EOS |
01065                                           DSI_DATA_AREA_PHYS);
01066     if(flags & DSI_DATA_AREA_PHYS)
01067       {
01068         *addr = (void*)socket->sg_lists[nr].addr;
01069         return -DSI_EPHYS;
01070       }
01071     else
01072       {
01073         *addr = socket->data_area + socket->sg_lists[nr].addr;
01074         if(!flags) return 0;
01075         if(flags & DSI_DATA_AREA_GAP) return -DSI_EGAP;
01076         return -DSI_EEOS;
01077       }
01078   } // normal case, packet had valid sg-number
01079   
01080   /* check if packet contains more data */
01081   if (packet->sg_idx == DSI_SG_ELEM_LAST)
01082     return -DSI_ENODATA;
01083   return -L4_EINVAL;
01084 }
01085 
01086 /*****************************************************************************/
01087 /**
01088  * \brief Set packet number.
01089  * \ingroup packet
01090  * 
01091  * \param socket         Socket descriptor
01092  * \param packet         Packet descriptor
01093  * \param np             Packet number
01094  *
01095  * \return 0 on success, error code otherwise:
01096  *         - -L4_EINVAL invalid socket or packet descriptor
01097  *
01098  * \note The packet number can be any desired number that makes the packet
01099  *       kind of unique.
01100  */
01101 /*****************************************************************************/ 
01102 int 
01103 dsi_packet_set_no(dsi_socket_t * socket, dsi_packet_t * packet,
01104                   l4_uint32_t no)
01105 {
01106 #if DO_SANITY
01107   /* check socket */
01108   if (!dsi_is_valid_socket(socket))
01109     return -L4_EINVAL;
01110 
01111   /* check packet */
01112   if (!__is_valid_packet(socket,packet))
01113     return -L4_EINVAL;
01114 
01115   /* only send components can set packet no */
01116   if (!IS_SEND_SOCKET(socket))
01117     return -L4_EINVAL;
01118 #endif
01119 
01120   /* set packet no */
01121   packet->no = no;
01122 
01123   /* done */
01124   return 0;
01125 }
01126 
01127 /*****************************************************************************/
01128 /**
01129  * \brief Get packet number
01130  * \ingroup packet
01131  * 
01132  * \param  socket        Socket descriptor
01133  * \param  packet        Packet descriptor
01134  * \retval no            Packet number
01135  * 
01136  * \return 0 on success (\a no contains packet number), error code otherwise:
01137  *         - -L4_EINVAL invalid socket or packet descriptor
01138  */
01139 /*****************************************************************************/ 
01140 int 
01141 dsi_packet_get_no(dsi_socket_t * socket, dsi_packet_t * packet,
01142                   l4_uint32_t * no)
01143 {
01144 #if DO_SANITY
01145   /* check socket */
01146   if (!dsi_is_valid_socket(socket))
01147     return -L4_EINVAL;
01148 
01149   /* check packet */
01150   if (!__is_valid_packet(socket,packet))
01151     return -L4_EINVAL;
01152 #endif
01153 
01154   *no = packet->no;
01155 
01156   /* done */
01157   return 0;
01158 }

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