Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rtmutex-tester.c
Go to the documentation of this file.
1 /*
2  * RT-Mutex-tester: scriptable tester for rt mutexes
3  *
4  * started by Thomas Gleixner:
5  *
6  * Copyright (C) 2006, Timesys Corp., Thomas Gleixner <[email protected]>
7  *
8  */
9 #include <linux/device.h>
10 #include <linux/kthread.h>
11 #include <linux/export.h>
12 #include <linux/sched.h>
13 #include <linux/spinlock.h>
14 #include <linux/timer.h>
15 #include <linux/freezer.h>
16 
17 #include "rtmutex.h"
18 
19 #define MAX_RT_TEST_THREADS 8
20 #define MAX_RT_TEST_MUTEXES 8
21 
22 static spinlock_t rttest_lock;
23 static atomic_t rttest_event;
24 
26  int opcode;
27  int opdata;
29  int event;
30  struct device dev;
31 };
32 
35 static struct rt_mutex mutexes[MAX_RT_TEST_MUTEXES];
36 
39  RTTEST_SCHEDOT, /* 1 Sched other, data = nice */
40  RTTEST_SCHEDRT, /* 2 Sched fifo, data = prio */
41  RTTEST_LOCK, /* 3 Lock uninterruptible, data = lockindex */
42  RTTEST_LOCKNOWAIT, /* 4 Lock uninterruptible no wait in wakeup, data = lockindex */
43  RTTEST_LOCKINT, /* 5 Lock interruptible, data = lockindex */
44  RTTEST_LOCKINTNOWAIT, /* 6 Lock interruptible no wait in wakeup, data = lockindex */
45  RTTEST_LOCKCONT, /* 7 Continue locking after the wakeup delay */
46  RTTEST_UNLOCK, /* 8 Unlock, data = lockindex */
47  /* 9, 10 - reserved for BKL commemoration */
48  RTTEST_SIGNAL = 11, /* 11 Signal other test thread, data = thread id */
49  RTTEST_RESETEVENT = 98, /* 98 Reset event counter */
50  RTTEST_RESET = 99, /* 99 Reset all pending operations */
51 };
52 
53 static int handle_op(struct test_thread_data *td, int lockwakeup)
54 {
55  int i, id, ret = -EINVAL;
56 
57  switch(td->opcode) {
58 
59  case RTTEST_NOP:
60  return 0;
61 
62  case RTTEST_LOCKCONT:
63  td->mutexes[td->opdata] = 1;
64  td->event = atomic_add_return(1, &rttest_event);
65  return 0;
66 
67  case RTTEST_RESET:
68  for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) {
69  if (td->mutexes[i] == 4) {
70  rt_mutex_unlock(&mutexes[i]);
71  td->mutexes[i] = 0;
72  }
73  }
74  return 0;
75 
76  case RTTEST_RESETEVENT:
77  atomic_set(&rttest_event, 0);
78  return 0;
79 
80  default:
81  if (lockwakeup)
82  return ret;
83  }
84 
85  switch(td->opcode) {
86 
87  case RTTEST_LOCK:
88  case RTTEST_LOCKNOWAIT:
89  id = td->opdata;
91  return ret;
92 
93  td->mutexes[id] = 1;
94  td->event = atomic_add_return(1, &rttest_event);
95  rt_mutex_lock(&mutexes[id]);
96  td->event = atomic_add_return(1, &rttest_event);
97  td->mutexes[id] = 4;
98  return 0;
99 
100  case RTTEST_LOCKINT:
102  id = td->opdata;
104  return ret;
105 
106  td->mutexes[id] = 1;
107  td->event = atomic_add_return(1, &rttest_event);
108  ret = rt_mutex_lock_interruptible(&mutexes[id], 0);
109  td->event = atomic_add_return(1, &rttest_event);
110  td->mutexes[id] = ret ? 0 : 4;
111  return ret ? -EINTR : 0;
112 
113  case RTTEST_UNLOCK:
114  id = td->opdata;
115  if (id < 0 || id >= MAX_RT_TEST_MUTEXES || td->mutexes[id] != 4)
116  return ret;
117 
118  td->event = atomic_add_return(1, &rttest_event);
119  rt_mutex_unlock(&mutexes[id]);
120  td->event = atomic_add_return(1, &rttest_event);
121  td->mutexes[id] = 0;
122  return 0;
123 
124  default:
125  break;
126  }
127  return ret;
128 }
129 
130 /*
131  * Schedule replacement for rtsem_down(). Only called for threads with
132  * PF_MUTEX_TESTER set.
133  *
134  * This allows us to have finegrained control over the event flow.
135  *
136  */
138 {
139  int tid, op, dat;
140  struct test_thread_data *td;
141 
142  /* We have to lookup the task */
143  for (tid = 0; tid < MAX_RT_TEST_THREADS; tid++) {
144  if (threads[tid] == current)
145  break;
146  }
147 
148  BUG_ON(tid == MAX_RT_TEST_THREADS);
149 
150  td = &thread_data[tid];
151 
152  op = td->opcode;
153  dat = td->opdata;
154 
155  switch (op) {
156  case RTTEST_LOCK:
157  case RTTEST_LOCKINT:
158  case RTTEST_LOCKNOWAIT:
160  if (mutex != &mutexes[dat])
161  break;
162 
163  if (td->mutexes[dat] != 1)
164  break;
165 
166  td->mutexes[dat] = 2;
167  td->event = atomic_add_return(1, &rttest_event);
168  break;
169 
170  default:
171  break;
172  }
173 
174  schedule();
175 
176 
177  switch (op) {
178  case RTTEST_LOCK:
179  case RTTEST_LOCKINT:
180  if (mutex != &mutexes[dat])
181  return;
182 
183  if (td->mutexes[dat] != 2)
184  return;
185 
186  td->mutexes[dat] = 3;
187  td->event = atomic_add_return(1, &rttest_event);
188  break;
189 
190  case RTTEST_LOCKNOWAIT:
192  if (mutex != &mutexes[dat])
193  return;
194 
195  if (td->mutexes[dat] != 2)
196  return;
197 
198  td->mutexes[dat] = 1;
199  td->event = atomic_add_return(1, &rttest_event);
200  return;
201 
202  default:
203  return;
204  }
205 
206  td->opcode = 0;
207 
208  for (;;) {
210 
211  if (td->opcode > 0) {
212  int ret;
213 
215  ret = handle_op(td, 1);
217  if (td->opcode == RTTEST_LOCKCONT)
218  break;
219  td->opcode = ret;
220  }
221 
222  /* Wait for the next command to be executed */
223  schedule();
224  }
225 
226  /* Restore previous command and data */
227  td->opcode = op;
228  td->opdata = dat;
229 }
230 
231 static int test_func(void *data)
232 {
233  struct test_thread_data *td = data;
234  int ret;
235 
236  current->flags |= PF_MUTEX_TESTER;
237  set_freezable();
239 
240  for(;;) {
241 
243 
244  if (td->opcode > 0) {
246  ret = handle_op(td, 0);
248  td->opcode = ret;
249  }
250 
251  /* Wait for the next command to be executed */
252  schedule();
253  try_to_freeze();
254 
255  if (signal_pending(current))
257 
258  if(kthread_should_stop())
259  break;
260  }
261  return 0;
262 }
263 
274 static ssize_t sysfs_test_command(struct device *dev, struct device_attribute *attr,
275  const char *buf, size_t count)
276 {
277  struct sched_param schedpar;
278  struct test_thread_data *td;
279  char cmdbuf[32];
280  int op, dat, tid, ret;
281 
282  td = container_of(dev, struct test_thread_data, dev);
283  tid = td->dev.id;
284 
285  /* strings from sysfs write are not 0 terminated! */
286  if (count >= sizeof(cmdbuf))
287  return -EINVAL;
288 
289  /* strip of \n: */
290  if (buf[count-1] == '\n')
291  count--;
292  if (count < 1)
293  return -EINVAL;
294 
295  memcpy(cmdbuf, buf, count);
296  cmdbuf[count] = 0;
297 
298  if (sscanf(cmdbuf, "%d:%d", &op, &dat) != 2)
299  return -EINVAL;
300 
301  switch (op) {
302  case RTTEST_SCHEDOT:
303  schedpar.sched_priority = 0;
304  ret = sched_setscheduler(threads[tid], SCHED_NORMAL, &schedpar);
305  if (ret)
306  return ret;
308  break;
309 
310  case RTTEST_SCHEDRT:
311  schedpar.sched_priority = dat;
312  ret = sched_setscheduler(threads[tid], SCHED_FIFO, &schedpar);
313  if (ret)
314  return ret;
315  break;
316 
317  case RTTEST_SIGNAL:
318  send_sig(SIGHUP, threads[tid], 0);
319  break;
320 
321  default:
322  if (td->opcode > 0)
323  return -EBUSY;
324  td->opdata = dat;
325  td->opcode = op;
326  wake_up_process(threads[tid]);
327  }
328 
329  return count;
330 }
331 
337 static ssize_t sysfs_test_status(struct device *dev, struct device_attribute *attr,
338  char *buf)
339 {
340  struct test_thread_data *td;
341  struct task_struct *tsk;
342  char *curr = buf;
343  int i;
344 
345  td = container_of(dev, struct test_thread_data, dev);
346  tsk = threads[td->dev.id];
347 
348  spin_lock(&rttest_lock);
349 
350  curr += sprintf(curr,
351  "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, M:",
352  td->opcode, td->event, tsk->state,
353  (MAX_RT_PRIO - 1) - tsk->prio,
354  (MAX_RT_PRIO - 1) - tsk->normal_prio,
355  tsk->pi_blocked_on);
356 
357  for (i = MAX_RT_TEST_MUTEXES - 1; i >=0 ; i--)
358  curr += sprintf(curr, "%d", td->mutexes[i]);
359 
360  spin_unlock(&rttest_lock);
361 
362  curr += sprintf(curr, ", T: %p, R: %p\n", tsk,
363  mutexes[td->dev.id].owner);
364 
365  return curr - buf;
366 }
367 
368 static DEVICE_ATTR(status, 0600, sysfs_test_status, NULL);
369 static DEVICE_ATTR(command, 0600, NULL, sysfs_test_command);
370 
371 static struct bus_type rttest_subsys = {
372  .name = "rttest",
373  .dev_name = "rttest",
374 };
375 
376 static int init_test_thread(int id)
377 {
378  thread_data[id].dev.bus = &rttest_subsys;
379  thread_data[id].dev.id = id;
380 
381  threads[id] = kthread_run(test_func, &thread_data[id], "rt-test-%d", id);
382  if (IS_ERR(threads[id]))
383  return PTR_ERR(threads[id]);
384 
385  return device_register(&thread_data[id].dev);
386 }
387 
388 static int init_rttest(void)
389 {
390  int ret, i;
391 
392  spin_lock_init(&rttest_lock);
393 
394  for (i = 0; i < MAX_RT_TEST_MUTEXES; i++)
395  rt_mutex_init(&mutexes[i]);
396 
397  ret = subsys_system_register(&rttest_subsys, NULL);
398  if (ret)
399  return ret;
400 
401  for (i = 0; i < MAX_RT_TEST_THREADS; i++) {
402  ret = init_test_thread(i);
403  if (ret)
404  break;
405  ret = device_create_file(&thread_data[i].dev, &dev_attr_status);
406  if (ret)
407  break;
408  ret = device_create_file(&thread_data[i].dev, &dev_attr_command);
409  if (ret)
410  break;
411  }
412 
413  printk("Initializing RT-Tester: %s\n", ret ? "Failed" : "OK" );
414 
415  return ret;
416 }
417 
418 device_initcall(init_rttest);