event.c

Go to the documentation of this file.
00001 /* $Id: event.c 23296 2005-11-19 18:52:14Z adam $ */
00002 /*****************************************************************************/
00003 /**
00004  * \file   dsi/lib/src/event.c
00005  * \brief  Event signalling thread
00006  *
00007  * \date   02/04/2001
00008  * \author Lars Reuther <reuther@os.inf.tu-dresden.de>
00009  */
00010 /*****************************************************************************/
00011 
00012 /* L4/DROPS includes */
00013 #include <l4/sys/types.h>
00014 #include <l4/sys/ipc.h>
00015 #include <l4/env/errno.h>
00016 #include <l4/util/macros.h>
00017 #include <l4/thread/thread.h>
00018 
00019 /* library includes */
00020 #include <l4/dsi/dsi.h>
00021 #include "__event.h"
00022 #include "__thread.h"
00023 #include "__config.h"
00024 #include "__debug.h"
00025 
00026 /*****************************************************************************
00027  *** global stuff
00028  *****************************************************************************/
00029 
00030 /// component event signalling thread id
00031 static l4_threadid_t dsi_component_event_id = L4_INVALID_ID;
00032 
00033 #define MAX_CLIENTS  (DSI_MAX_EVENTS * DSI_MAX_SOCKETS)
00034 
00035 /// client descriptors 
00036 static dsi_event_client_t clients[MAX_CLIENTS];
00037 
00038 /// IPC commands 
00039 #define EVENT_SET    0x00000000
00040 #define EVENT_RESET  0x40000000
00041 #define EVENT_WAIT   0x80000000
00042 
00043 #define EVENT_MASK   ((1UL << DSI_MAX_EVENTS) - 1)
00044 
00045 /* prototypes */
00046 static void
00047 __event_thread(void * data);
00048 
00049 /*****************************************************************************/
00050 /**
00051  * \brief Init event signalling.
00052  * \ingroup internal
00053  */
00054 /*****************************************************************************/ 
00055 void
00056 dsi_init_event_signalling(void)
00057 {
00058   int i;
00059 
00060   /* start signalling thread */
00061   dsi_component_event_id = dsi_create_event_thread(__event_thread);
00062 
00063   for (i = 0; i < MAX_CLIENTS; i++)
00064     clients[i].events = 0;
00065 }
00066 
00067 /*****************************************************************************
00068  *** Component event handling
00069  *****************************************************************************/
00070 
00071 /*****************************************************************************/
00072 /**
00073  * \brief Send event notification to client application.
00074  * \ingroup internal
00075  * 
00076  * \param  client        Client thread id
00077  * \param  events        Event mask
00078  * \param  error         Error code to be sent to the client
00079  * 
00080  * \return 0 on success (sent notification), -L4_EIPC on error
00081  */
00082 /*****************************************************************************/ 
00083 static inline int
00084 __client_wakeup(l4_threadid_t client, l4_uint32_t events, int error)
00085 {
00086   int ret;
00087   l4_msgdope_t result;
00088 
00089   /* send notification */
00090   ret = l4_ipc_send(client,L4_IPC_SHORT_MSG,error,events,
00091                          L4_IPC_SEND_TIMEOUT_0,&result);
00092   if ((ret == 0) || (ret == L4_IPC_SETIMEOUT)) 
00093     return 0;
00094   else 
00095     {
00096       LOG_Error("DSI: send event notification failed (0x%02x)",ret);
00097       return -L4_EIPC;
00098     }
00099 }
00100   
00101 /*****************************************************************************/
00102 /**
00103  * \brief Set events.
00104  * \ingroup internal
00105  *
00106  * \param  id            Socket id
00107  * \param  events        Event mask
00108  *      
00109  * \return 0 on success (incremented event counter), error code otherwise:
00110  *         - \c -L4_EINVAL  invalid socket id
00111  *         - \c -L4_EIPC    IPC error sending wakeup message
00112  *
00113  * Increment event counter for the vents specified in \a events and wakeup
00114  * clients waiting for those events.
00115  */
00116 /*****************************************************************************/ 
00117 static int
00118 __set_event(dsi_socketid_t id, l4_uint32_t events)
00119 {
00120   dsi_socket_t * s;
00121   int ret,i,error;
00122   dsi_event_client_t * c;
00123   dsi_event_client_t * tmp;
00124 
00125   LOGdL(DEBUG_EVENT,"socket %d, events 0x%08x",id,events);
00126 
00127   /* get socket descriptor */
00128   ret = dsi_socket_get_descriptor(id,&s);
00129   if (ret)
00130     {
00131       LOG_Error("DSI: invalid socket id (%d)",id);
00132       return -L4_EINVAL;
00133     }
00134 
00135   /* increment event counter */
00136   for (i = 0; i < DSI_MAX_EVENTS; i++)
00137     {
00138       if (events & (1UL << i))
00139         /* set event i */
00140         s->events[i]++;
00141     }
00142 
00143   /* is somebody waiting for one of the events? */
00144   error = 0;
00145   if (s->waiting & events)
00146     {
00147       c = s->clients;
00148       tmp = NULL;
00149       while (c)
00150         {
00151           if (c->events & events)
00152             {
00153               /* wakeup client */
00154               ret = __client_wakeup(c->id,c->events & events,0);
00155               if (ret)
00156                 error = ret;
00157 
00158               /* remove waiting flags */
00159               s->waiting &= ~(c->events);
00160 
00161               /* release client descriptor */
00162               c->events = 0;
00163 
00164               /* remove from wait queue */
00165               if (tmp == NULL)
00166                 {
00167                   s->clients = c->next; 
00168                   c = s->clients;
00169                 }
00170               else
00171                 {
00172                   tmp->next = c->next;
00173                   c = c->next;
00174                 }
00175             }
00176           else
00177             {
00178               tmp = c;
00179               c = c->next;
00180             }
00181         } 
00182     }
00183 
00184   /* done */
00185   return error;
00186 }
00187 
00188 /*****************************************************************************/
00189 /**
00190  * \brief Reset events.
00191  * \ingroup internal
00192  * 
00193  * \param  client        Client thread id
00194  * \param  id            Socket id
00195  * \param  events        Event mask
00196  *              
00197  * \return 0 on succes (decremented event counter), error code otherwise:
00198  *         - \c -L4_EINVAL  invalid socket id or event mask
00199  */
00200 /*****************************************************************************/ 
00201 static int 
00202 __reset_event(l4_threadid_t client, dsi_socketid_t id, l4_uint32_t events)
00203 {
00204   dsi_socket_t * s;
00205   int ret,i,error;
00206 
00207   LOGdL(DEBUG_EVENT,"socket %d, events 0x%08x",id,events);
00208 
00209   /* get socket descriptor */
00210   ret = dsi_socket_get_descriptor(id,&s);
00211   if (ret)
00212     {
00213       LOG_Error("DSI: invalid socket id (%d)",id);
00214       return -L4_EINVAL;
00215     }
00216 
00217   /* increment event counter */
00218   error = 0;
00219   for (i = 0; i < DSI_MAX_EVENTS; i++)
00220     {
00221       if (events & (1UL << i))
00222         {
00223           if (s->events[i] > 0)
00224             s->events[i]--;
00225           else
00226             {
00227               LOG_Error("DSI: event 0x%08x not set",1U << i);
00228               error = -L4_EINVAL;
00229             }
00230         }
00231     }
00232 
00233   /* done */
00234   return error;
00235 }
00236 
00237 /*****************************************************************************/
00238 /**
00239  * \brief Wait for events.
00240  * \ingroup internal
00241  * 
00242  * \param  client        Client thread id
00243  * \param  id            Socket id
00244  * \param  events        Event mask
00245  *      
00246  * \return 0 on success (registered client), error code otherwise:
00247  *         - \c -L4_EINVAL  invalid socket id
00248  *         - \c -L4_EBUSY   someone else already registered for one of
00249  *                          the events
00250  *
00251  * Register the client for event notification. If one of the events is 
00252  * already set, wakeup client immediately.
00253  */
00254 /*****************************************************************************/ 
00255 static int
00256 __wait_for_events(l4_threadid_t client, dsi_socketid_t id, l4_uint32_t events)
00257 {
00258   dsi_socket_t * s;
00259   int ret,i;
00260   l4_uint32_t mask;
00261   dsi_event_client_t * c;
00262 
00263   /* get socket descriptor */
00264   ret = dsi_socket_get_descriptor(id,&s);
00265   if (ret)
00266     {
00267       LOG_Error("DSI: invalid socket id (%d)",id);
00268       return -L4_EINVAL;
00269     }
00270   
00271   /* other clients already registered for one of the events? */
00272   if (s->waiting & events)
00273     return -L4_EBUSY;
00274 
00275   /* events already set? */
00276   mask = 0;
00277   for (i = 0; i < DSI_MAX_EVENTS; i++)
00278     {
00279       if ((events & (1U << i)) && (s->events[i] > 0))
00280         mask |= (1U << i);
00281     }
00282 
00283   if (mask)
00284     __client_wakeup(client,mask,0);
00285   else
00286     {
00287       /* enqueue client */
00288       i = 0;
00289       while ((i < MAX_CLIENTS) && (clients[i].events != 0))
00290         i++;
00291 
00292       if (i == MAX_CLIENTS)
00293         {
00294           /* this should never happen, there should be enough descriptors 
00295            * to store the maximum number of clients (one separate client
00296            * for each possible event).
00297            */
00298           Panic("DSI: wait for event: no client descriptor available!");
00299           return -L4_EINVAL;
00300         }
00301 
00302       /* setup client descriptor */
00303       clients[i].id = client;
00304       clients[i].events = events;
00305       clients[i].next = NULL;
00306 
00307       /* insert into sockest client wait queue */
00308       if (s->clients == NULL)
00309         s->clients = &clients[i];
00310       else
00311         {
00312           c = s->clients;
00313           while (c->next != NULL)
00314             c = c->next;
00315           c->next = &clients[i];
00316         }
00317 
00318       /* mark events waiting */
00319       s->waiting |= events;
00320     }
00321 
00322   /* done */
00323   return 0;
00324 }
00325 
00326 /*****************************************************************************/
00327 /**
00328  * \brief Component event signalling thread.
00329  * \ingroup internal
00330  * 
00331  * \param  data          Thread data (unused).
00332  *
00333  * IPC protocol
00334  *
00335  * request:
00336  *   dw0 bits 31/30 command
00337  *                  0 ... set events (only allowed by other threads of the
00338  *                        component)
00339  *                  1 ... reset events
00340  *                  2 ... wait for events
00341  *       bits 29-0  event mask
00342  *   dw1 socket id
00343  *
00344  * reply:
00345  *   dw0 error code
00346  *   dw1 event mask (reply for EVENT_WAIT)
00347  */
00348 /*****************************************************************************/ 
00349 static void
00350 __event_thread(void * data)
00351 {
00352   l4_threadid_t me = l4thread_l4_id(l4thread_myself());
00353   l4_threadid_t src;
00354   int ret,error,reply;
00355   l4_umword_t dw0,dw1;
00356   l4_msgdope_t result;
00357   int cmd;
00358 
00359   LOGdL(DEBUG_EVENT,"signalling thread up.");
00360 
00361   /* thread loop */
00362   while (1)
00363     {
00364       ret = l4_ipc_wait(&src,L4_IPC_SHORT_MSG,&dw0,&dw1,
00365                              L4_IPC_NEVER,&result);
00366       while (!ret)
00367         {
00368           LOGdL(DEBUG_EVENT,"request: dw0 0x%08lx, dw1 %ld", dw0, dw1);
00369 
00370           reply = 1;
00371           cmd = dw0 & ~EVENT_MASK;
00372 
00373           switch (cmd)
00374             {
00375             case EVENT_SET:
00376               /* set events */
00377               if (l4_task_equal(src,me))
00378                 error = __set_event(dw1,dw0 & EVENT_MASK);
00379               else
00380                 error = -L4_EPERM;
00381               break;
00382 
00383             case EVENT_RESET:
00384               /* reset events */
00385               error = __reset_event(src,dw1,dw0 & EVENT_MASK);
00386               break;
00387 
00388             case EVENT_WAIT:
00389               /* wait for events */
00390               error = __wait_for_events(src,dw1,dw0 & EVENT_MASK);
00391               if (!error)
00392                 reply = 0;
00393               break;
00394 
00395             default:
00396               /* invalid request */
00397               LOG_Error("DSI: event signalling thread: invalid request 0x%08lx",
00398                         dw0);
00399               error = -L4_EINVAL;
00400             }
00401 
00402           if (reply)
00403             ret = l4_ipc_reply_and_wait(src,L4_IPC_SHORT_MSG,error,0,
00404                                              &src,L4_IPC_SHORT_MSG,&dw0,&dw1,
00405                                              L4_IPC_SEND_TIMEOUT_0,
00406                                              &result);
00407           else
00408             ret = l4_ipc_wait(&src,L4_IPC_SHORT_MSG,&dw0,&dw1,
00409                                    L4_IPC_SEND_TIMEOUT_0,&result);
00410         }
00411 
00412       LOG_Error("DSI: event signalling thread IPC error 0x%02x",ret);
00413     }
00414 
00415   /* this should never happen */
00416   Panic("left event signalling thread!"); 
00417 }
00418 
00419 /*****************************************************************************/
00420 /**
00421  * \brief Set events
00422  * \ingroup internal
00423  * 
00424  * \param  socket_id     Socket id
00425  * \param  events        Event mask
00426  *      
00427  * \return 0 on success (called signalling thread to set events), 
00428  *         error code otherwise:
00429  *         - \c -L4_EINVAL  invalid socket id
00430  *         - \c -L4_EIPC    IPC error sending wakeup message to client
00431  *
00432  * Call event signalling thread to set events. All the manipulation of the 
00433  * event counter and wait queues is done by the signalling thread to ensure
00434  * synchronization with client requests. 
00435  */
00436 /*****************************************************************************/ 
00437 int 
00438 dsi_event_set(dsi_socketid_t socket_id, l4_uint32_t events)
00439 {
00440   int ret, error;
00441   l4_umword_t dummy;
00442   l4_msgdope_t result;
00443 
00444   /* call signalling thread */
00445   ret = l4_ipc_call(dsi_component_event_id,L4_IPC_SHORT_MSG,
00446                          EVENT_SET | (events & EVENT_MASK),socket_id,
00447                          L4_IPC_SHORT_MSG,(l4_umword_t *)&error,&dummy,
00448                          L4_IPC_NEVER,&result);
00449   if (ret)
00450     {
00451       LOG_Error("DSI: error calling event signalling thread (0x%02x)!",ret);
00452       return -L4_EIPC;
00453     }
00454  
00455   /* done */
00456   return error;
00457 }
00458 
00459 /*****************************************************************************/
00460 /**
00461  * \brief Return id of event signalling thread.
00462  * \ingroup component 
00463  * 
00464  * \return Thread id.
00465  */
00466 /*****************************************************************************/ 
00467 l4_threadid_t
00468 dsi_get_event_thread_id(void)
00469 {
00470   /* return thread id */
00471   return dsi_component_event_id;
00472 }
00473 
00474 /*****************************************************************************
00475  *** Application event handling
00476  *****************************************************************************/
00477 
00478 /*****************************************************************************/
00479 /**
00480  * \brief Reset events
00481  * \ingroup internal
00482  * 
00483  * \param  event_thread  Event signalling thread id
00484  * \param  socket_id     Socket id
00485  * \param  events        Event mask 
00486  *      
00487  * \return 0 on success (called components event signalling thread), 
00488  *         error code otherwise:
00489  *         - \c -L4_EIPC    error calling signalling thread
00490  *         - \c -L4_EINVAL  invalid socket id or event mask
00491  */
00492 /*****************************************************************************/ 
00493 int
00494 dsi_event_reset(l4_threadid_t event_thread, dsi_socketid_t socket_id,
00495                 l4_uint32_t events)
00496 {
00497   int ret,error;
00498   l4_umword_t dummy;
00499   l4_msgdope_t result;
00500 
00501   /* call component */
00502   ret = l4_ipc_call(event_thread,L4_IPC_SHORT_MSG,
00503                          EVENT_RESET | (events & EVENT_MASK),socket_id,
00504                          L4_IPC_SHORT_MSG,(l4_umword_t *)&error,&dummy,
00505                          L4_IPC_NEVER,&result);
00506   if (ret)
00507     {
00508       LOG_Error("DSI: error calling components event signalling thread (0x%02x)!",
00509                 ret);
00510       return -L4_EIPC;
00511     }
00512 
00513   /* done */
00514   return error;
00515 }
00516 
00517 /*****************************************************************************/
00518 /**
00519  * \brief Wait for events
00520  * \ingroup internal
00521  * 
00522  * \param  event_thread  Event signalling thread id
00523  * \param  socket_id     Socket id
00524  * \param  events        Event mask
00525  *      
00526  * \return Event mask set by the component (> 0), error code otherwise:
00527  *         - \c -L4_EIPC    error calling signalling thread
00528  *         - \c -L4_EINVAL  invalid socket id
00529  *         - \c -L4_EBUSY   another client is already registered for one
00530  *                          of the events
00531  *
00532  * Wait for the notification by the component that one of the events in 
00533  * \a events is set.
00534  */
00535 /*****************************************************************************/ 
00536 l4_int32_t
00537 dsi_event_wait(l4_threadid_t event_thread, dsi_socketid_t socket_id,
00538                l4_uint32_t events)
00539 {
00540   int ret,error;
00541   l4_int32_t mask;
00542   l4_msgdope_t result;
00543 
00544   /* call component */
00545   ret = l4_ipc_call(event_thread,L4_IPC_SHORT_MSG,
00546                          EVENT_WAIT | (events & EVENT_MASK),socket_id,
00547                          L4_IPC_SHORT_MSG,(l4_umword_t *)&error,
00548                          (l4_umword_t *)&mask,
00549                          L4_IPC_NEVER,&result);
00550   if (ret)
00551     {
00552       LOG_Error("DSI: error calling components event signalling thread (0x%02x)!",
00553                 ret);
00554       return -L4_EIPC;
00555     }
00556      
00557   /* done */
00558   if (error)
00559     return error;
00560   else
00561     return mask;
00562 }

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