cp: implement mutex dependency tracking
[hvf.git] / cp / nucleus / ldep.c
bloba1b5fb710b9d17584bf6a1417c1458540ccc0f50
1 /*
2 * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <sched.h>
9 #include <list.h>
10 #include <spinlock.h>
11 #include <ldep.h>
13 static spinlock_t __lock = SPIN_LOCK_UNLOCKED;
14 static int ldep_enabled;
16 void ldep_on()
18 unsigned long mask;
20 spin_lock_intsave(&__lock, &mask);
21 ldep_enabled = 1;
22 spin_unlock_intrestore(&__lock, mask);
25 static int __get_stack_slot()
27 current->nr_locks++;
29 if (current->nr_locks == LDEP_STACK_SIZE) {
30 con_printf(NULL, "task '%s' exceeded the number of tracked "
31 "locks (%d)! disabling ldep!\n", current->name,
32 LDEP_STACK_SIZE);
33 return 1;
36 return 0;
39 static void print_held_locks()
41 struct held_lock *cur;
42 int i;
44 con_printf(NULL, "\nlocks currently held:\n");
45 for(i=0; i<current->nr_locks; i++) {
46 cur = &current->lock_stack[i];
47 con_printf(NULL, " #%d: (%s), at %p\n", i, cur->lockname,
48 cur->ra);
52 void ldep_lock(void *lock, struct lock_class *c, char *lockname)
54 void *ra = __builtin_return_address(0);
55 struct held_lock *cur;
56 unsigned long mask;
58 // LOCK
59 spin_lock_intsave(&__lock, &mask);
61 if (!ldep_enabled)
62 goto out;
64 /* ok, no issues, add the lock we're trying to get to the stack */
65 if (__get_stack_slot())
66 goto out;
68 cur = &current->lock_stack[current->nr_locks-1];
69 cur->ra = ra;
70 cur->lock = lock;
71 cur->lockname = lockname;
73 out:
74 // UNLOCK
75 spin_unlock_intrestore(&__lock, mask);
78 void ldep_unlock(void *lock, char *lockname)
80 void *ra = __builtin_return_address(0);
81 struct held_lock *cur;
82 unsigned long mask;
83 int i;
85 // LOCK
86 spin_lock_intsave(&__lock, &mask);
88 if (!ldep_enabled)
89 goto out;
91 for(i=0; i<current->nr_locks; i++) {
92 cur = &current->lock_stack[i];
93 if (cur->lock == lock)
94 goto found;
97 con_printf(NULL, "task '%s' is trying to release lock it doesn't have:\n",
98 current->name);
99 con_printf(NULL, " (%s), at %p\n", lockname, ra);
100 print_held_locks();
102 ldep_enabled = 0;
104 goto out;
106 found:
107 if (i != current->nr_locks-1)
108 memcpy(&current->lock_stack[i],
109 &current->lock_stack[i+1],
110 current->nr_locks - i - 1);
112 current->nr_locks--;
114 out:
115 // UNLOCK
116 spin_unlock_intrestore(&__lock, mask);
119 void ldep_no_locks()
121 void *ra = __builtin_return_address(0);
122 unsigned long mask;
124 // LOCK
125 spin_lock_intsave(&__lock, &mask);
127 if (!ldep_enabled)
128 goto out;
130 if (!current->nr_locks)
131 goto out;
133 con_printf(NULL, "task '%s' is holding a lock when it shouldn't have:\n",
134 current->name);
135 con_printf(NULL, " at %p\n", ra);
136 print_held_locks();
138 ldep_enabled = 0;
140 out:
141 // UNLOCK
142 spin_unlock_intrestore(&__lock, mask);