summaryrefslogtreecommitdiff
path: root/viengoos/mutex.h
blob: f6ed2ffe5fb0fab4aee6a95629651d413f7009b4 (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
/* mutex.c - Small, simple LIFO mutex implementation.
   Copyright (C) 2007 Free Software Foundation, Inc.
   Written by Neal H. Walfield <neal@gnu.org>.

   This file is part of the GNU Hurd.

   GNU Hurd is free software: you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

   GNU Hurd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with GNU Hurd.  If not, see
   <http://www.gnu.org/licenses/>.  */

#ifndef _MUTEX_H
#define _MUTEX_H

#include <l4/thread.h>
#include <atomic.h>
#include <assert.h>
#include <hurd/lock.h>

typedef l4_thread_id_t ss_mutex_t;

/* Used by the atomic operations.  */
extern void abort (void);

static inline void
ss_mutex_lock (__const char *caller, int line, ss_mutex_t *lock)
{
  l4_thread_id_t owner;

  for (;;)
    {
      owner = atomic_exchange_acq (lock, l4_myself ());
      if (owner == l4_nilthread)
	{
	  ss_mutex_trace_add (SS_MUTEX_LOCK, caller, line, lock);
	  return;
	}
  
      ss_mutex_trace_add (SS_MUTEX_LOCK_WAIT, caller, line, lock);

      if (owner == l4_myself ())
	ss_lock_trace_dump (lock);
      assert (owner != l4_myself ());

      __ss_lock_wait (l4_anylocalthread);
    }
}

#define ss_mutex_lock(__sml_lockp)					\
  do									\
    {									\
      debug (5, "ss_mutex_lock (%p)", __sml_lockp);			\
      ss_mutex_lock (__func__, __LINE__, __sml_lockp);			\
    }									\
  while (0)

static inline void
ss_mutex_unlock (__const char *caller, int line, ss_mutex_t *lock)
{
  l4_thread_id_t waiter;

  waiter = atomic_exchange_acq (lock, l4_nilthread);
  ss_mutex_trace_add (SS_MUTEX_UNLOCK, caller, line, lock);
  if (waiter == l4_myself ())
    /* No waiter.  */
    return;

  if (waiter == l4_nilthread)
    ss_lock_trace_dump (lock);
  assert (waiter != l4_nilthread);

  /* Signal the waiter.  */
  __ss_lock_wakeup (waiter);
}

#define ss_mutex_unlock(__smu_lockp)					\
  do									\
    {									\
      debug (5, "ss_mutex_unlock (%p)", __smu_lockp);			\
      ss_mutex_unlock (__func__, __LINE__, __smu_lockp);		\
    }									\
  while (0)

static inline bool
ss_mutex_trylock (__const char *caller, int line, ss_mutex_t *lock)
{
  l4_thread_id_t owner;

  owner = atomic_compare_and_exchange_val_acq (lock, l4_myself (),
					       l4_nilthread);
  if (owner == l4_nilthread)
    {
      ss_mutex_trace_add (SS_MUTEX_TRYLOCK, caller, line, lock);
      return true;
    }

  // ss_mutex_trace_add (SS_MUTEX_TRYLOCK_BLOCKED, caller, line, lock);

  return false;
}

#define ss_mutex_trylock(__sml_lockp)					\
  ({									\
    bool __sml_r = ss_mutex_trylock (__func__, __LINE__, __sml_lockp);	\
    debug (5, "ss_mutex_trylock (%p) -> %s",				\
	   __sml_lockp, __sml_r ? "t" : "f");				\
    __sml_r;								\
  })

#endif