00001 /* $Id: convenience.c 23331 2005-11-21 09:35:18Z fm3 $ */ 00002 /*****************************************************************************/ 00003 /** 00004 * \file dsi/lib/src/convenience.c 00005 * 00006 * \brief Convinience functions for our poor users. 00007 * 00008 * \date 05/15/2001 00009 * \author Jork Loeser <jork.loeser@inf.tu-dresden.de> 00010 * 00011 */ 00012 /*****************************************************************************/ 00013 00014 #include <l4/env/errno.h> 00015 #include <l4/sys/types.h> 00016 #include <l4/sys/ipc.h> 00017 #include <l4/thread/thread.h> 00018 #include <l4/log/l4log.h> 00019 00020 #include <l4/dsi/dsi.h> 00021 #include "__debug.h" 00022 #include "__config.h" 00023 00024 /**************************************************************************** 00025 * 00026 * Threading issues 00027 * 00028 ****************************************************************************/ 00029 00030 /*! 00031 * \brief Send start message to work thread and wait for ready-notification. 00032 * \ingroup thread 00033 * 00034 * We start the work-thread and wait until it gives an ok.. 00035 * 00036 * \param socket socket descriptor 00037 * \param ret_code (optional) pointer to the return-code provided 00038 * by the worker-thread with dsi_thread_worker_started() 00039 * \retval 0 on success 00040 * \retval -DROPS_EIPC error sending start IPC 00041 * 00042 * The intention of this function is to be used by the creator of a 00043 * socket in conjunction with dsi_thread_worker_wait() used by the 00044 * worker thread. If the creator creates a worker-thread that handles 00045 * the socket, it cannot create the socket prior to the worker-thread, 00046 * because the worker-id is needed for socket-creation. Thus, the 00047 * worker-thread must be created and wait to be notified about the 00048 * socket then. 00049 */ 00050 int dsi_thread_start_worker(dsi_socket_t * socket, 00051 l4_umword_t * ret_code){ 00052 int ret; 00053 l4_msgdope_t result; 00054 l4_umword_t d1, *dp; 00055 00056 dp=ret_code?ret_code:&d1; 00057 00058 /* send start IPC */ 00059 ret = l4_ipc_send(socket->work_th,L4_IPC_SHORT_MSG,(l4_umword_t)socket,0, 00060 L4_IPC_NEVER,&result); 00061 if (ret) return -L4_EIPC; 00062 00063 ret = l4_ipc_receive(socket->work_th, L4_IPC_SHORT_MSG, 00064 dp, &d1, L4_IPC_NEVER, &result); 00065 if(ret) return -L4_EIPC; 00066 00067 return 0; 00068 } 00069 00070 00071 /*! 00072 * \brief Wait until our parent sends the socket. 00073 * \ingroup thread 00074 * 00075 * \param socket will be filled with the socket descriptor 00076 * \retval 0 on success, IPC-error otherwise 00077 * 00078 * This function should be called by a worker-thread after it was created 00079 * by its parent. It informs the caller about the socket to use. 00080 * 00081 * \note This function is only useful in conjunction with 00082 * dsi_thread_start_worker(). 00083 */ 00084 int dsi_thread_worker_wait(dsi_socket_t ** socket){ 00085 int ret; 00086 l4_msgdope_t result; 00087 l4_umword_t dw1; 00088 l4_threadid_t parentid; 00089 00090 parentid = l4thread_l4_id (l4thread_get_parent ()); 00091 00092 /* wait for start notification */ 00093 ret = l4_ipc_receive(parentid,L4_IPC_SHORT_MSG, 00094 (l4_umword_t *)socket,&dw1, 00095 L4_IPC_NEVER,&result); 00096 return ret; 00097 } 00098 00099 /*! 00100 * \brief Send ready-notification to parent thread. 00101 * \ingroup thread 00102 * 00103 * \param ret_code code to be send to the parent 00104 * \retval 0 on success 00105 * \retval -DROPS_EIPC error sending start IPC 00106 * 00107 * This function should be used by a worker thread to indicate that it 00108 * started. An error-code can be passed to the parent. 00109 */ 00110 int dsi_thread_worker_started(int ret_code){ 00111 int ret; 00112 l4_msgdope_t result; 00113 l4_threadid_t parentid; 00114 00115 parentid = l4thread_l4_id (l4thread_get_parent ()); 00116 00117 /* send start IPC */ 00118 ret = l4_ipc_send(parentid,L4_IPC_SHORT_MSG,ret_code,0, 00119 L4_IPC_NEVER,&result); 00120 if (ret) return -L4_EIPC; 00121 return 0; 00122 } 00123 00124 00125 00126 /**************************************************************************** 00127 * 00128 * Default Handlers 00129 * 00130 ****************************************************************************/ 00131 00132 /*!\brief Open-function for use with local sockets 00133 * \ingroup socket 00134 * 00135 * \param cfg low level stream configuration 00136 * \param ctrl_ds control area (if invalid, allocate new area) 00137 * \param data_ds data area 00138 * \param work_id work thread id 00139 * \param flags socket flags, see dsi_socket_create() 00140 * \param socket ptr to a #dsi_socket_t pointer, that will be set to 00141 * the newly created socket. Ignored if 0. 00142 * \param comp ptr to a #dsi_component_t structure, that will be 00143 * filled in 00144 * 00145 * This function can be used to create a component with a local socket in it. 00146 * Use this function if your application is endpoint of a communication as 00147 * well. 00148 * 00149 * The start and stop entries in comp will be set to 0. If you want a 00150 * notification of this events, set your own callbacks after calling. 00151 * 00152 * \see dsi_socket_create(). 00153 */ 00154 int dsi_socket_local_create(dsi_stream_cfg_t cfg, 00155 l4dm_dataspace_t *ctrl_ds, 00156 l4dm_dataspace_t *data_ds, 00157 l4_threadid_t work_id, 00158 l4_uint32_t flags, 00159 dsi_socket_t **socket, 00160 dsi_component_t *comp){ 00161 00162 l4_threadid_t sync= L4_INVALID_ID; 00163 int err; 00164 dsi_socket_t *s; 00165 00166 if(!socket)socket=&s; 00167 if((err = dsi_socket_create((dsi_jcp_stream_t){}, cfg, 00168 ctrl_ds, data_ds, work_id, 00169 &sync, flags, 00170 socket))!=0){ 00171 return err; 00172 } 00173 if((err = dsi_socket_get_ref(*socket, &comp->socketref))!=0){ 00174 dsi_socket_close(*socket); 00175 return err; 00176 } 00177 comp->connect = dsi_socket_local_connect; 00178 comp->start = 0; 00179 comp->stop = dsi_socket_local_stop; 00180 comp->close = dsi_socket_local_close; 00181 return 0; 00182 } 00183 00184 /*!\brief Close-function for use with local socket refs 00185 * \ingroup socket 00186 * 00187 * This callback can be used for the close-callback in a DSI 00188 * component descriptor (#dsi_component_t) if the socket is a socket in 00189 * the local address space, and no other actions must be performed on 00190 * connecting a socket than to call dsi_socket_close(). 00191 * 00192 * \see dsi_socket_connect(). 00193 */ 00194 int dsi_socket_local_close(dsi_component_t *comp){ 00195 int err; 00196 dsi_socket_t *socket; 00197 00198 if((err = dsi_socket_get_descriptor(comp->socketref.socket, 00199 &socket))!=0){ 00200 return err; 00201 } 00202 return dsi_socket_close(socket); 00203 } 00204 00205 /*!\brief Stop-function for use with local socket refs 00206 * \ingroup socket 00207 * 00208 * This callback can be used for the stop-callback in a DSI 00209 * component descriptor (#dsi_component_t) if the socket is a socket in 00210 * the local address space, and no other actions must be performed on 00211 * connecting a socket than to call dsi_socket_stop(). 00212 * 00213 * \see dsi_socket_connect(). 00214 */ 00215 int dsi_socket_local_stop(dsi_component_t *comp){ 00216 int err; 00217 dsi_socket_t *socket; 00218 00219 if((err = dsi_socket_get_descriptor(comp->socketref.socket, 00220 &socket))!=0){ 00221 return err; 00222 } 00223 return dsi_socket_stop(socket); 00224 } 00225 00226 /*!\brief Connect-function for use with local socket refs 00227 * \ingroup socket 00228 * 00229 * This callback can be used for the connect-callback in a DSI 00230 * component descriptor (#dsi_component_t) if the socket is a socket in 00231 * the local address space, and no other actions must be performed on 00232 * connecting a socket than to call dsi_socket_connect(). 00233 * 00234 * \see dsi_socket_connect(). 00235 */ 00236 int dsi_socket_local_connect(dsi_component_t *comp, 00237 dsi_socket_ref_t *remote){ 00238 dsi_socket_t *socket; 00239 int ret; 00240 00241 LOGd_Enter(DEBUG_CONNECT, "id %d -> id %d", comp->socketref.socket, 00242 remote->socket); 00243 if((ret=dsi_socket_get_descriptor(comp->socketref.socket,&socket))!=0) 00244 return ret; 00245 return dsi_socket_connect(socket, remote); 00246 } 00247