/ README.LINUX_SERVER
README.LINUX_SERVER
1 *** SERVING LINUX SYSCALLS IN RTAI HARD REAL TIME MODE *** 2 3 The default RTAI way of dealing with Linux syscalls done while in hard real 4 time consists in moving a task wanting to use Linux back to soft mode, 5 recovering it to hard real time again, as soon as possible, afterward. See the 6 related RTAI configuration helper for an explanation of the different available 7 modes to implement the "as soon as possible" above on various architectures. 8 9 This README documents possible alternative ways to access Linux services from 10 hard real time RTAI applications in user space. Such a support is based on the 11 creation of a general purpose server thread that takes over Linux requests. 12 13 It must be noticed that if Linux is to be used synchronously at the very moment 14 Linux is called the task becomes timed by Linux, wherever a Linux server is 15 used or not. So hard real time constraints cannot be satisfied anyhow. The use 16 of a Linux server has an advantage though. In fact it takes just two context 17 switches, in place of the four used by hard-soft-hard transitions. Moreover it 18 ensures that RTAI returns to hard real time immediately after the Linux syscall 19 has finished while, if the architecture does not support the immediate Linux 20 syscall mode reliably for all Linux syscalls, there will be the need to wait 21 for a call to an RTAI function to go back in RTAI hard real time fully. That 22 will add even far more latencies when a hard RTAI task does some processing 23 for a significant amount of time after the Linux syscall, without using any 24 RTAI service. So, provided it is allowed loosing real time, installing a 25 synchronous server might be the best way to interact with Linux anyhow. 26 27 There are however instances in which Linux can be used asynchronously. In 28 such cases RTAI hard real time tasks might use Linux without loosing hard 29 real time determinism. Such a capability can be implemented in many ways, 30 the one chosen by RTAI is based on a buffering of async Linux syscalls mated 31 either to an optional callback function or to inquiry mechanisms to help 32 implementing any user own async call policy. Beware of not reusing read/write 33 data buffers made available to async calls though. 34 If you do not want, or cannot, either inquire for or check async terminations, 35 to avoid running the risk of reusing an yet unserved buffer, use RTAI dynamic 36 memory or SCB to allocate them in real time, freeing them afterward, possibly 37 with the help of a support callback function. 38 Async support is a bit tricky but, provided one cares of what said above, it 39 should work always when Linux syscalls arguments are fully contained in the 40 passed registers structure. That is not the case for a few Linux syscalls that 41 are multiplexed within a single framework, whereas libc can end in building a 42 hidden object on the stack, so that it is not assured it will be available at 43 the time the server uses it. On some archs a notable example of that is the 44 socketcall, but RTAI should already care of it appropriately. There remain 45 nonetheless the chance of other instances to be cared as well. So beware that 46 some async calls might not work with a few Linux services yet, in which case 47 you should let us know about it for a possible fix. 48 Just to mention another typical care to be taken we notice that printf might 49 work as it is but it will often crash. So the safe way to printf is as follows: 50 - sprintf(buffer, format, args, ....); 51 - write(STDOUT_FILENO, buffer, strlen(buffer)); 52 53 Provided the socketcall has been intercepted well you should be able to do many 54 IO operations asynchronously, e.g.: dumping data directly to disk, Linux ipcs 55 and POSIX mq, fifos, pipes, serial and networked communications etc. etc. 56 In many applications one often requires RTAI specific IO drivers just to avoid 57 loosing real time for communications with non real time support/interface 58 processes and tasks. The async server should be of much help in such cases by 59 letting you use standard Linux, with the ensuing advantage of not needing any 60 special hard real time driver. 61 62 Clearly what above does not impede you to set up your own async server to 63 which your hard real time task can be connected by using RTAI non blocking 64 communication functions, i.e. those ending with "_if". So the choice of the 65 most viable solution is left to you. 66 67 How it works 68 ------------ 69 70 By using the functions described below a server thread is created that will 71 block waiting for parent task requests to Linux. Whenever the RTAI scheduler 72 intercepts a Linux syscall in hard real time mode it passes it to the server 73 thread and: 74 - remains waiting for its execution if in sync mode; 75 - returns immediately if in async mode. 76 The server carries out the syscall and: 77 - resumes the hard real time parent, returning what returned by Linux, if in 78 sync mode: 79 - calls a callback function, if one has been made available, in async mode, 80 returning an identifier. 81 82 As said in sync mode real time is lost, but there will be two task switches per 83 Linux service request only, while there will be four if no sync server is used. 84 In async mode there is no need for any task switch, as the server will execute 85 in soft mode when there will be no RTAI real time activity any more. 86 The need of passing syscall data to the server is responsible for most of the 87 penalty incurred by using a Linux server. 88 Let's stress once more that this is a far better alternative way to what the 89 RTAI scheduler will have to do anyhow, i.e. make you soft and recover hard mode 90 at the next RTAI proper service call, which will require four task switches, 91 keeping you in Linux hands from the Linux syscall till an RTAI function is 92 called again. 93 With a server instead you will stay soft just either till Linux has finished 94 servicing your request, when in sync mode, or kept working in real time, when 95 in async mode. 96 97 API Functions prototypes 98 ------------------------ 99 100 The available functions are: 101 102 - void *rt_create_linux_syscall_server(RT_TASK *task, int mode, void 103 (*callback_fun)(long, long), int nr_bufd_async_calls); 104 create a Linux syscall server for task, a NULL task means the current one; a 105 non NULL return is the handle allowing you to link to the server for any 106 further management request, see functions below, NULL indicates a failure in 107 setting the server up; a NULL callback_fun is allowed. It will operate 108 according to mode setting, either SYNC_LINUX_SYSCALL or ASYNC_LINUX_SYSCALL. 109 Beware of using an appropriate nr_bufd_async_calls. If async requests overrun 110 the latest will be discarded till some space is available again. 111 If a server exists already it is terminated and a new one replaces it. 112 113 - void rt_destroy_linux_syscall(RT_TASK *task); 114 destroy the linux_syscall_server of task, if NULL use the current task. 115 116 - void *rt_sync_async_linux_syscall_server_create(RT_TASK *task, int mode, 117 void (*callback_fun)(long, long), int nr_bufd_async_calls); 118 legacy interface, the same as: 119 rt_create_linux_syscall_server(task, mode, callback_fun, nr_bufd_async_calls). 120 121 - void *rt_linux_syscall_server_create(RT_TASK *task); 122 legacy call, the same as: 123 rt_create_linux_syscall_server(task, SYNC_LINUX_SYSCALL, NULL, 1). 124 125 Notice that in sync mode Linux functions will return their usual values while 126 that is not possible in async mode and what returned is an identifier, id, of 127 that specific async call, a negative id meaning the call was not satisfied 128 because of a buffer overrun. When <= 0 ids can be used for monitoring async 129 calls execution, as explained below. 130 131 - int rt_set_linux_syscall_mode(int mode, void (*callback_fun)(long, long); 132 to both switch between sync and async mode and change the call back function. 133 It returns EINVAL if there is no server or the mode setting is not correct. 134 135 Notice that this is a legacy call, you'd better use: 136 137 - int rt_linux_syscall_mode(struct linux_syscalls_list *syscalls, int mode); 138 to switch between sync and async mode; syscalls is the handle returned by 139 rt_sync_async_linux_syscall_server_create; mode can be: SYNC_LINUX_SYSCALL, 140 ASYNC_LINUX_SYSCALL, LINUX_SYSCALL_GET_MODE. 141 The function returns the previous mode and LINUX_SYSCALL_GET_MODE can be used 142 to just inquire for it, in which case mode is discarded. EINVAL is returned if 143 syscalls is not a valid pointer. 144 145 - void *rt_linux_syscall_cbfun(struct linux_syscalls_list *syscalls, void (*cbfun)(long, long)); 146 to change the callback function; syscalls is the handle returned by 147 rt_sync_async_linux_syscall_server_create; cbfun can be either a NULL, no 148 callback will be used, a pointer to a true callback function, 149 LINUX_SYSCALL_GET_CALLBACK. 150 The function returns the pointer to the previous callback function and 151 LINUX_SYSCALL_GET_CALLBACK can be used to just inquire for it. EINVAL is 152 returned if syscall is not a valid pointer 153 154 The callback function afford a notification control mechanism for async calls. 155 An alternative way to monitor async calls execution is given by the following 156 functions: 157 158 - int rt_linux_syscall_status(struct linux_syscalls_list *syscalls, int id, int *retval); 159 syscalls is the handle returned from rt_sync_async_linux_syscall_server_create; 160 id is the value returned by the call to Linux, retval is a pointer to an int 161 that will receive the value returned by Linux after executing the related 162 service. 163 It returns: 164 - EINVAL if syscalls is not a valid pointer or id < 0 165 - ENOENT if no id is found, meaning the function has been overwritten; 166 - ECANCELED when the function has call has been explicitly canceled by the 167 user; 168 - EINPROGRESS when the function is pending waiting for execution; 169 - 0 when the function has been executed, in such a case retval, if not NULL, 170 will receive the value returned by Linux. 171 172 - int rt_linux_syscall_cancel(struct linux_syscalls_list *syscalls, int id); 173 Syscalls is the handle returned from rt_sync_async_linux_syscall_server_create; 174 id is the value returned by the call to Linux. 175 It returns: 176 - EINVAL if syscalls is not a valid pointer or id < 0 177 - ENOENT if no id is found, meaning the function has been overwritten; 178 - -id when the function has been executed already; 179 - 0 if the function has been successfully canceled. 180 181 Examples 182 ------- 183 184 They are in RTAI "showroom" CVS: linux_server and printer_server. 185 186 Paolo.