summaryrefslogtreecommitdiffstats
path: root/include/sys/mutex.h
blob: 2db4a7f96d8307f2c1969986ba11c37a02c66a1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#ifndef _SPL_MUTEX_H
#define	_SPL_MUTEX_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <linux/module.h>
#include <sys/types.h>

/* See the "Big Theory Statement" in solaris mutex.c.
 *
 * Spin mutexes apparently aren't needed by zfs so we assert
 * if ibc is non-zero.
 *
 * Our impementation of adaptive mutexes aren't really adaptive.
 * They go to sleep every time.
 */

#define MUTEX_DEFAULT		0
#define MUTEX_HELD(x)           (mutex_owned(x))

#define KM_MAGIC		0x42424242
#define KM_POISON		0x84

typedef struct {
	int km_magic;
	char *km_name;
	struct task_struct *km_owner;
	struct semaphore km_sem;
} kmutex_t;

#undef mutex_init
static __inline__ void
mutex_init(kmutex_t *mp, char *name, int type, void *ibc)
{
	BUG_ON(ibc != NULL);		/* XXX - Spin mutexes not needed? */
	BUG_ON(type != MUTEX_DEFAULT);	/* XXX - Only default type supported? */

	mp->km_magic = KM_MAGIC;
	sema_init(&mp->km_sem, 1);
	mp->km_owner = NULL;
	mp->km_name = NULL;

	if (name) {
		mp->km_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
		if (mp->km_name)
			strcpy(mp->km_name, name);
	}
}

#undef mutex_destroy
static __inline__ void
mutex_destroy(kmutex_t *mp)
{
	BUG_ON(mp->km_magic != KM_MAGIC);

	if (mp->km_name)
		kfree(mp->km_name);

	memset(mp, KM_POISON, sizeof(*mp));
}

static __inline__ void
mutex_enter(kmutex_t *mp)
{
	BUG_ON(mp->km_magic != KM_MAGIC);
	down(&mp->km_sem);  /* Will check in_atomic() for us */
	BUG_ON(mp->km_owner != NULL);
	mp->km_owner = current;
}

/* Return 1 if we acquired the mutex, else zero.
 */
static __inline__ int
mutex_tryenter(kmutex_t *mp)
{
	int result;

	BUG_ON(mp->km_magic != KM_MAGIC);
	result = down_trylock(&mp->km_sem); /* returns 0 if acquired */
	if (result == 0) {
		BUG_ON(mp->km_owner != NULL);
		mp->km_owner = current;
		return 1;
	}
	return 0;
}

static __inline__ void
mutex_exit(kmutex_t *mp)
{
	BUG_ON(mp->km_magic != KM_MAGIC);
	BUG_ON(mp->km_owner != current);
	mp->km_owner = NULL;
	up(&mp->km_sem);
}

/* Return 1 if mutex is held by current process, else zero.
 */
static __inline__ int
mutex_owned(kmutex_t *mp)
{
	BUG_ON(mp->km_magic != KM_MAGIC);
	return (mp->km_owner == current);
}

/* Return owner if mutex is owned, else NULL.
 */
static __inline__ kthread_t *
mutex_owner(kmutex_t *mp)
{
	BUG_ON(mp->km_magic != KM_MAGIC);
	return mp->km_owner;
}

#ifdef	__cplusplus
}
#endif

#endif	/* _SPL_MUTEX_H */