base/tasklets/signal.c

Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2006 Paolo Mantegazza <mantegazza@aero.polimi.it> 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License as 00006 * published by the Free Software Foundation; either version 2 of the 00007 * License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 */ 00018 00019 00020 #include <linux/kernel.h> 00021 #include <linux/module.h> 00022 00023 #include <rtai_schedcore.h> 00024 #include <rtai_signal.h> 00025 00026 MODULE_LICENSE("GPL"); 00027 #define MODULE_NAME "RTAI_SIGNALS" 00028 00029 #define RT_SCHED_SIGSUSP (1 << 15) 00030 00031 #define RT_SIGNALS ((struct rt_signal_t *)task->rt_signals) 00032 struct rt_signal_t { unsigned long flags; RT_TASK *sigtask; }; 00033 00034 static int rt_request_signal_(RT_TASK *sigtask, RT_TASK *task, long signal) 00035 { 00036 int retval; 00037 if (signal >= 0 && sigtask && task) { 00038 if (!task->rt_signals) { 00039 task->rt_signals = rt_malloc(MAXSIGNALS*sizeof(struct rt_signal_t)); 00040 task->pstate = 0; 00041 } 00042 RT_SIGNALS[signal].flags = (1 << SIGNAL_ENBIT); 00043 RT_SIGNALS[signal].sigtask = sigtask; 00044 retval = 0; 00045 } else { 00046 retval = -EINVAL; 00047 } 00048 task->retval = retval; 00049 rt_task_resume(task); 00050 return retval; 00051 } 00052 EXPORT_SYMBOL(rt_request_signal_); 00053 00054 static inline void rt_exec_signal(RT_TASK *sigtask, RT_TASK *task) 00055 { 00056 unsigned long flags; 00057 00058 flags = rt_global_save_flags_and_cli(); 00059 if (!(--sigtask->suspdepth)) { 00060 if (task) { 00061 sigtask->priority = task->priority; 00062 if (!task->pstate++) { 00063 rem_ready_task(task); 00064 task->state |= RT_SCHED_SIGSUSP; 00065 } 00066 } 00067 sigtask->state &= ~RT_SCHED_SIGSUSP; 00068 sigtask->retval = (long)task; 00069 enq_ready_task(sigtask); 00070 RT_SCHEDULE(sigtask, rtai_cpuid()); 00071 } 00072 rt_global_restore_flags(flags); 00073 } 00074 00075 /** 00076 * Release a signal previously requested for a task. 00077 * 00078 * @param signal, >= 0, is the signal. 00079 * 00080 * @param task is the task for which the signal was previously requested. 00081 * 00082 * A call of this function will release a signal previously requested for 00083 * a task. 00084 * 00085 * @retval 0 on success. 00086 * @return -EINVAL in case of error. 00087 * 00088 */ 00089 00090 int rt_release_signal(long signal, RT_TASK *task) 00091 { 00092 if (task == NULL) { 00093 task = RT_CURRENT; 00094 } 00095 if (signal >= 0 && RT_SIGNALS && RT_SIGNALS[signal].sigtask) { 00096 RT_SIGNALS[signal].sigtask->priority = task->priority; 00097 rt_exec_signal(RT_SIGNALS[signal].sigtask, 0); 00098 return 0; 00099 } 00100 return -EINVAL; 00101 } 00102 EXPORT_SYMBOL(rt_release_signal); 00103 00104 /** 00105 * Trigger a signal for a task (i.e. send a signal to the task), executing 00106 * the related handler. 00107 * 00108 * @param signal, >= 0, is the signal. 00109 * 00110 * @param task is the task to which the signal is sent. 00111 * 00112 * A call of this function will stop the task served by signal, if executing, 00113 * till the triggered handler has finished its execution, carried out at the 00114 * same priority and on the same CPU of the task it is serving. 00115 * 00116 */ 00117 00118 void rt_trigger_signal(long signal, RT_TASK *task) 00119 { 00120 if (task == NULL) { 00121 task = RT_CURRENT; 00122 } 00123 if (signal >= 0 && RT_SIGNALS && RT_SIGNALS[signal].sigtask) { 00124 do { 00125 if (test_and_clear_bit(SIGNAL_ENBIT, &RT_SIGNALS[signal].flags)) { 00126 rt_exec_signal(RT_SIGNALS[signal].sigtask, task); 00127 test_and_set_bit(SIGNAL_ENBIT, &RT_SIGNALS[signal].flags); 00128 } else { 00129 test_and_set_bit(SIGNAL_PNDBIT, &RT_SIGNALS[signal].flags); 00130 break; 00131 } 00132 } while (test_and_clear_bit(SIGNAL_PNDBIT, &RT_SIGNALS[signal].flags)); 00133 } 00134 } 00135 EXPORT_SYMBOL(rt_trigger_signal); 00136 00137 /** 00138 * Enable a signal for a task. 00139 * 00140 * @param signal, >= 0, is the signal. 00141 * 00142 * @param task is the task which signal is enabled. 00143 * 00144 * A call of this function will enable reception of the related signal by 00145 * task. 00146 * 00147 */ 00148 00149 void rt_enable_signal(long signal, RT_TASK *task) 00150 { 00151 if (task == NULL) { 00152 task = RT_CURRENT; 00153 } 00154 if (signal >= 0 && RT_SIGNALS) { 00155 set_bit(SIGNAL_ENBIT, &RT_SIGNALS[signal].flags); 00156 } 00157 } 00158 EXPORT_SYMBOL(rt_enable_signal); 00159 00160 /** 00161 * disable a signal for a task. 00162 * 00163 * @param signal, >= 0, is the signal. 00164 * 00165 * @param task is the task which signal is enabled. 00166 * 00167 * A call of this function will disable reception of the related signal by 00168 * task. 00169 * 00170 */ 00171 00172 void rt_disable_signal(long signal, RT_TASK *task) 00173 { 00174 if (task == NULL) { 00175 task = RT_CURRENT; 00176 } 00177 if (signal >= 0 && RT_SIGNALS) { 00178 clear_bit(SIGNAL_ENBIT, &RT_SIGNALS[signal].flags); 00179 } 00180 } 00181 EXPORT_SYMBOL(rt_disable_signal); 00182 00183 static int rt_signal_helper(RT_TASK *task) 00184 { 00185 if (task) { 00186 rt_task_suspend(task); 00187 return task->retval; 00188 } 00189 return (RT_CURRENT)->runnable_on_cpus; 00190 } 00191 00192 int rt_wait_signal(RT_TASK *sigtask, RT_TASK *task) 00193 { 00194 unsigned long flags; 00195 00196 flags = rt_global_save_flags_and_cli(); 00197 if (!sigtask->suspdepth++) { 00198 sigtask->state |= RT_SCHED_SIGSUSP; 00199 rem_ready_current(sigtask); 00200 if (task->pstate > 0 && !(--task->pstate) && (task->state &= ~RT_SCHED_SIGSUSP) == RT_SCHED_READY) { 00201 enq_ready_task(task); 00202 } 00203 rt_schedule(); 00204 } 00205 rt_global_restore_flags(flags); 00206 return sigtask->retval; 00207 } 00208 EXPORT_SYMBOL(rt_wait_signal); 00209 00210 static void signal_suprt_fun(struct sigsuprt_t *funarg) 00211 { 00212 struct sigsuprt_t arg = *funarg; 00213 00214 arg.sigtask = RT_CURRENT; 00215 if (!rt_request_signal_(arg.sigtask, arg.task, arg.signal)) { 00216 while (rt_wait_signal(arg.sigtask, arg.task)) { 00217 arg.sighdl(arg.signal, arg.task); 00218 } 00219 } else { 00220 rt_task_resume(arg.task); 00221 } 00222 } 00223 00224 /** 00225 * Install a handler for catching RTAI real time async signals. 00226 * 00227 * @param signal, >= 0, is the signal. 00228 * 00229 * @param sighdl is the handler that will execute upon signal reception. 00230 * 00231 * RTAI real time signal handlers are executed within a host hard real time 00232 * thread, assigned to the same CPU of the receiving task, while the task 00233 * receiving the signal is kept stopped. No difference between kernel and 00234 * user space, the usual symmetric usage. 00235 * If the request is succesfull the function will return with signal reception 00236 * enabled. 00237 * 00238 * @retval 0 on success. 00239 * @return -EINVAL in case of error. 00240 * 00241 */ 00242 00243 int rt_request_signal(long signal, void (*sighdl)(long, RT_TASK *)) 00244 { 00245 if (signal >= 0 && sighdl) { 00246 RT_TASK *task = RT_CURRENT; 00247 struct sigsuprt_t arg = { NULL, task, signal, sighdl, task->runnable_on_cpus }; 00248 if ((task = rt_malloc(sizeof(RT_TASK)))) { 00249 rt_task_init_cpuid(task, (void *)signal_suprt_fun, (long)&arg, SIGNAL_TASK_STACK_SIZE, arg.task->priority, 0, 0, arg.cpuid); 00250 rt_task_resume(task); 00251 rt_task_suspend(arg.task); 00252 return arg.task->retval; 00253 } 00254 } 00255 return -EINVAL; 00256 } 00257 EXPORT_SYMBOL(rt_request_signal); 00258 00259 static struct rt_fun_entry rtai_signals_fun[] = { 00260 [SIGNAL_HELPER] = { 1, rt_signal_helper }, // internal, not for users 00261 [SIGNAL_WAITSIG] = { 1, rt_wait_signal }, // internal, not for users 00262 [SIGNAL_REQUEST] = { 1, rt_request_signal_ }, // internal, not for users 00263 [SIGNAL_RELEASE] = { 1, rt_release_signal }, 00264 [SIGNAL_ENABLE] = { 1, rt_enable_signal }, 00265 [SIGNAL_DISABLE] = { 1, rt_disable_signal }, 00266 [SIGNAL_TRIGGER] = { 1, rt_trigger_signal } 00267 }; 00268 00269 int init_module(void) 00270 { 00271 if (set_rt_fun_ext_index(rtai_signals_fun, RTAI_SIGNALS_IDX)) { 00272 printk("Wrong or already used LXRT extension: %d.\n", RTAI_SIGNALS_IDX); 00273 return -EACCES; 00274 } 00275 printk("%s: loaded.\n", MODULE_NAME); 00276 return 0; 00277 } 00278 00279 void cleanup_module(void) 00280 { 00281 reset_rt_fun_ext_index(rtai_signals_fun, RTAI_SIGNALS_IDX); 00282 printk("%s: unloaded.\n", MODULE_NAME); 00283 }

Generated on Thu Nov 20 11:49:53 2008 for RTAI API by doxygen 1.3.8