base/include/rtai_scb.h

Go to the documentation of this file.
00001 /**
00002  * @ingroup shm
00003  * @file
00004  *
00005  * SCB stand for Shared (memory) Circular Buffer. It is a non blocking
00006  * implementation for just a single writer (producer) and reader
00007  * (consumer) and, under such a constraint, it can be a specific
00008  * substitute for RTAI mailboxes. There are other constraints that
00009  * must be satisfied, so it cannot be a general substitute for the more
00010  * flexible RTAI mailboxes. In fact it provides just functions
00011  * corresponding to RTAI mailboxes non blocking atomic send/receive of
00012  * messages, i.e. the equivalents of rt_mbx_send_if and
00013  * rt_mbx_receive_if. Moreover the circular buffer size must be >= to
00014  * the largest message to be sent/received. At least the double of the 
00015  * largest message to be sent/received is strongly recommended.
00016  * Thus sending/receiving a message either succeeds of fails. However 
00017  * thanks to the use of shared memory it should be more efficient than
00018  * mailboxes in atomic exchanges of messages from kernel to user space.
00019  * So it is a good candidate for supporting drivers development.
00020  *
00021  * @author Paolo Mantegazza
00022  *
00023  * @note Copyright &copy; 2004-2008 Paolo Mantegazza <mantegazza@aero.polimi.it>
00024  *
00025  * This program is free software; you can redistribute it and/or
00026  * modify it under the terms of the GNU General Public License as
00027  * published by the Free Software Foundation; either version 2 of the
00028  * License, or (at your option) any later version.
00029  *
00030  * This program is distributed in the hope that it will be useful,
00031  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00032  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00033  * GNU General Public License for more details.
00034  *
00035  * You should have received a copy of the GNU General Public License
00036  * along with this program; if not, write to the Free Software
00037  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00038  */
00039 
00040 #ifndef _RTAI_SCB_H
00041 #define _RTAI_SCB_H
00042 
00043 #include <rtai_shm.h>
00044 #include <asm/rtai_atomic.h>
00045 
00046 #define SCB     ((void *)(scb))
00047 #define SIZE    ((volatile int *)scb)[-3]
00048 #define FBYTE   ((volatile int *)scb)[-2]
00049 #define LBYTE   ((volatile int *)scb)[-1]
00050 #define HDRSIZ  (3*sizeof(int))
00051 
00052 struct task_struct;
00053 
00054 #ifdef __KERNEL__
00055 
00056 #define RTAI_SCB_PROTO(type, name, arglist)  static inline type name arglist
00057 
00058 #else
00059 
00060 #define RTAI_SCB_PROTO  RTAI_PROTO
00061 
00062 #endif
00063 
00064 /**
00065  * Allocate and initialize a shared memory circular buffer.
00066  *
00067  * @internal
00068  *
00069  * rt_scb_init is used to allocate and/or initialize a shared memory circular
00070  * buffer.
00071  *
00072  * @param name is an unsigned long identifier;
00073  *
00074  * @param size is the size of the circular buffer.
00075  *
00076  * @param suprt is the kernel allocation method to be used, it can be:
00077  * - USE_VMALLOC, use vmalloc;
00078  * - USE_GFP_KERNEL, use kmalloc with GFP_KERNEL;
00079  * - USE_GFP_ATOMIC, use kmalloc with GFP_ATOMIC;
00080  * - USE_GFP_DMA, use kmalloc with GFP_DMA.
00081  * - for use in kernel/(multi-threaded)user space only applications the 
00082  *   user can use "suprt" to pass the address of any memory area (s)he has
00083  *   allocated on her/his own. In such a case the actual buffer should be
00084  *   greater than the requested size by the amount HDRSIZ at least.
00085  *
00086  * Since @a an unsigned long can be a clumsy identifier, services are provided
00087  * to convert 6 characters identifiers to unsigned long, and vice versa.
00088  *
00089  * @see nam2num() and num2nam().
00090  *
00091  * It must be remarked that only the very first call does a real allocation,
00092  * any following call to allocate with the same name, from anywhere, will just
00093  * increase the usage count and map the circular buffer to the user space, or 
00094  * return the related pointer to the already allocated buffer in kernel/user
00095  * space.
00096  * In any case the functions return a pointer to the circular buffer,
00097  * appropriately mapped to the memory space in use. So if one is really sure
00098  * that the named circular buffer has been initted already parameters "size"
00099  * and "suprt" are not used and can be assigned any value.
00100  *
00101  * @returns a valid address on succes, you must use it, 0 on failure.
00102  *
00103  */
00104 
00105 RTAI_SCB_PROTO(void *, rt_scb_init, (unsigned long name, int size, unsigned long suprt))
00106 {   
00107     void *scb;
00108     if (suprt > 1000) {
00109         size -=  HDRSIZ + 1;
00110         scb = (void *)suprt;
00111     } else {
00112         scb = rt_shm_alloc(name, size + HDRSIZ + 1, suprt);
00113     }
00114     if (scb && !atomic_cmpxchg((atomic_t *)scb, 0, name)) {
00115         ((int *)scb)[1] = ((int *)scb)[2] = 0;
00116         ((int *)scb)[0] = size + 1;
00117     } else {
00118         while (!((int *)scb)[0]);
00119     }           
00120     return scb ? scb + HDRSIZ : 0;
00121 }
00122 
00123 /**
00124  * Reset a shared memory circular buffer.
00125  *
00126  * @internal
00127  *
00128  * rt_scb_reset reinitializes a shared memory circular buffer.
00129  *
00130  * @param scb is the pointer returned when the buffer was initted.
00131  *
00132  */
00133 
00134 RTAI_SCB_PROTO(void, rt_scb_reset, (void *scb))
00135 { 
00136     LBYTE = FBYTE = 0;
00137 }
00138 
00139 /**
00140  * Free a shared memory circular buffer.
00141  *
00142  * @internal
00143  *
00144  * rt_scb_delete is used to release a previously allocated shared memory 
00145  * circular buffer.
00146  *
00147  * @param name is the unsigned long identifier used when the buffer was
00148  * allocated;
00149  *
00150  * Analogously to what done by all the named allocation functions the freeing
00151  * calls have just the effect of decrementing a usage count, unmapping any
00152  * user space shared memory being freed, till the last is done, as that is the
00153  * one the really frees any allocated memory.
00154  *
00155  * @returns the size of the succesfully freed buffer, 0 on failure.
00156  *
00157  * No need to call this function if you provided your own memory for the
00158  * circular buffer. 
00159  *
00160  */
00161 
00162 RTAI_SCB_PROTO(int, rt_scb_delete, (unsigned long name))
00163 { 
00164     return rt_shm_free(name);
00165 }
00166 
00167 /**
00168  * Get the number of bytes avaiable in a shared memory circular buffer.
00169  *
00170  * @internal
00171  *
00172  * rt_scb_avbs is used to get the number of bytes avaiable in a shared 
00173  * memory circular buffer.
00174  *
00175  * @param scb is the pointer handle returned when the buffer was initted.
00176  *
00177  * @returns the available number of bytes.
00178  *
00179  */
00180 
00181 RTAI_SCB_PROTO (int, rt_scb_avbs, (void *scb))
00182 { 
00183     int size = SIZE, fbyte = FBYTE, lbyte = LBYTE;
00184     return (lbyte >= fbyte ? lbyte - fbyte : size + lbyte - fbyte);
00185 }
00186 
00187 /**
00188  * Get the number of bytes avaiable in a shared memory circular buffer.
00189  *
00190  * @internal
00191  *
00192  * rt_scb_bytes is used to get the number of bytes avaiable in a shared 
00193  * memory circular buffer; legacy alias for rt_scb_avbs.
00194  *
00195  * @param scb is the pointer handle returned when the buffer was initted.
00196  *
00197  * @returns the available number of bytes.
00198  *
00199  */
00200 
00201 RTAI_SCB_PROTO (int, rt_scb_bytes, (void *scb))
00202 { 
00203     return rt_scb_avbs(scb);
00204 }
00205 
00206 /**
00207  * Get the number of free bytes pace in a shared memory circular buffer.
00208  *
00209  * @internal
00210  *
00211  * rt_scb_frbs is used to get the number of free bytes space avaiable in a 
00212  * shared memory circular buffer.
00213  *
00214  * @param scb is the pointer handle returned when the buffer was initted.
00215  *
00216  * @returns the number of free bytes.
00217  *
00218  */
00219 
00220 RTAI_SCB_PROTO (int, rt_scb_frbs, (void *scb))
00221 { 
00222     int size = SIZE, fbyte = FBYTE, lbyte = LBYTE;
00223     return (fbyte <= lbyte ? size + fbyte - lbyte : size - lbyte);
00224 }
00225 
00226 /**
00227  * @brief Gets (receives) a message, only if the whole message can be passed 
00228  * all at once.
00229  *
00230  * rt_scb_get tries to atomically receive the message @e msg of @e
00231  * msg_size bytes from the shared memory circular buffer @e scb.
00232  * It returns immediately and the caller is never blocked.
00233  *
00234  * @return On success, i.e. message got, it returns 0, msg_size on failure.
00235  *
00236  */
00237 
00238 RTAI_SCB_PROTO(int, rt_scb_get, (void *scb, void *msg, int msg_size))
00239 { 
00240     int size = SIZE, fbyte = FBYTE, lbyte = LBYTE;
00241     if (msg_size > 0 && ((lbyte -= fbyte) >= 0 ? lbyte : size + lbyte) >= msg_size) {
00242         int tocpy;
00243         if ((tocpy = size - fbyte) > msg_size) {
00244             memcpy(msg, SCB + fbyte, msg_size);
00245             FBYTE = fbyte + msg_size;
00246         } else {
00247             memcpy(msg, SCB + fbyte, tocpy);
00248             memcpy(msg + tocpy, SCB, msg_size -= tocpy);
00249             FBYTE = msg_size;
00250         }
00251         return 0;
00252     }
00253     return msg_size;
00254 }
00255 
00256 /**
00257  * @brief eavedrops a message.
00258  *
00259  * rt_scb_evdrp atomically spies the message @e msg of @e
00260  * msg_size bytes from the shared memory circular buffer @e scb.
00261  * It returns immediately and the caller is never blocked. It is like 
00262  * rt_scb_get but leaves the message in the shared memory circular buffer.
00263  *
00264  * @return On success, i.e. message got, it returns 0, msg_size on failure.
00265  *
00266  */
00267 
00268 RTAI_SCB_PROTO(int, rt_scb_evdrp, (void *scb, void *msg, int msg_size))
00269 { 
00270     int size = SIZE, fbyte = FBYTE, lbyte = LBYTE;
00271     if (msg_size > 0 && ((lbyte -= fbyte) >= 0 ? lbyte : size + lbyte) >= msg_size) {
00272         int tocpy;
00273         if ((tocpy = size - fbyte) > msg_size) {
00274             memcpy(msg, SCB + fbyte, msg_size);
00275         } else {
00276             memcpy(msg, SCB + fbyte, tocpy);
00277             memcpy(msg + tocpy, SCB, msg_size - tocpy);
00278         }
00279         return 0;
00280     }
00281     return msg_size;
00282 }
00283 
00284 /**
00285  * @brief Puts (sends) a message, only if the whole message can be passed all
00286  * at once.
00287  *
00288  * rt_scb_put tries to atomically send the message @e msg of @e
00289  * msg_size bytes to the shared memory circular buffer @e scb. 
00290  * It returns immediately and the caller is never blocked.
00291  *
00292  * @return On success, i.e. message put, it returns 0, msg_size on failure.
00293  *
00294  */
00295 
00296 RTAI_SCB_PROTO(int, rt_scb_put, (void *scb, void *msg, int msg_size))
00297 { 
00298     int size = SIZE, fbyte = FBYTE, lbyte = LBYTE;
00299     if (msg_size > 0 && ((fbyte -= lbyte) <= 0 ? size + fbyte : fbyte) > msg_size) {
00300         int tocpy;
00301         if ((tocpy = size - lbyte) > msg_size) {
00302             memcpy(SCB + lbyte, msg, msg_size);
00303             LBYTE = lbyte + msg_size;
00304         } else {
00305             memcpy(SCB + lbyte, msg, tocpy);
00306             memcpy(SCB, msg + tocpy, msg_size -= tocpy);
00307             LBYTE = msg_size;
00308         }
00309         return 0;
00310     }
00311     return msg_size;
00312 }
00313 
00314 RTAI_SCB_PROTO(int, rt_scb_ovrwr, (void *scb, void *msg, int msg_size))
00315 { 
00316     int size = SIZE, lbyte = LBYTE;
00317     if (msg_size > 0 && msg_size < size) {
00318         int tocpy;
00319         if ((tocpy = size - lbyte) > msg_size) {
00320             memcpy(SCB + lbyte, msg, msg_size);
00321             LBYTE = lbyte + msg_size;
00322         } else {
00323             memcpy(SCB + lbyte, msg, tocpy);
00324             memcpy(SCB, msg + tocpy, msg_size -= tocpy);
00325             LBYTE = msg_size;
00326         }
00327         return 0;
00328     }
00329     return msg_size;
00330 }
00331 
00332 #endif /* _RTAI_SCB_H */

Generated on Tue Feb 2 17:46:05 2010 for RTAI API by  doxygen 1.4.7