1 | /*
|
---|
2 | * Copyright (c) 2006 Ondrej Palkovsky
|
---|
3 | * All rights reserved.
|
---|
4 | *
|
---|
5 | * Redistribution and use in source and binary forms, with or without
|
---|
6 | * modification, are permitted provided that the following conditions
|
---|
7 | * are met:
|
---|
8 | *
|
---|
9 | * - Redistributions of source code must retain the above copyright
|
---|
10 | * notice, this list of conditions and the following disclaimer.
|
---|
11 | * - Redistributions in binary form must reproduce the above copyright
|
---|
12 | * notice, this list of conditions and the following disclaimer in the
|
---|
13 | * documentation and/or other materials provided with the distribution.
|
---|
14 | * - The name of the author may not be used to endorse or promote products
|
---|
15 | * derived from this software without specific prior written permission.
|
---|
16 | *
|
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
27 | */
|
---|
28 |
|
---|
29 | #ifndef LIBC_PRIVATE_FIBRIL_H_
|
---|
30 | #define LIBC_PRIVATE_FIBRIL_H_
|
---|
31 |
|
---|
32 | #include <adt/list.h>
|
---|
33 | #include <context.h>
|
---|
34 | #include <tls.h>
|
---|
35 | #include <abi/proc/uarg.h>
|
---|
36 | #include <fibril.h>
|
---|
37 | #include <ipc/common.h>
|
---|
38 |
|
---|
39 | #include "./futex.h"
|
---|
40 |
|
---|
41 | typedef struct {
|
---|
42 | fibril_t *fibril;
|
---|
43 | } fibril_event_t;
|
---|
44 |
|
---|
45 | #define FIBRIL_EVENT_INIT ((fibril_event_t) {0})
|
---|
46 |
|
---|
47 | struct fibril {
|
---|
48 | // XXX: The first two fields must not move (for taskdump).
|
---|
49 | link_t all_link;
|
---|
50 | context_t ctx;
|
---|
51 |
|
---|
52 | uspace_arg_t uarg;
|
---|
53 | link_t link;
|
---|
54 | void *stack;
|
---|
55 | size_t stack_size;
|
---|
56 | void *arg;
|
---|
57 | errno_t (*func)(void *);
|
---|
58 | tcb_t *tcb;
|
---|
59 |
|
---|
60 | fibril_t *clean_after_me;
|
---|
61 | errno_t retval;
|
---|
62 |
|
---|
63 | fibril_t *thread_ctx;
|
---|
64 |
|
---|
65 | bool is_running : 1;
|
---|
66 | bool is_writer : 1;
|
---|
67 | /* In some places, we use fibril structs that can't be freed. */
|
---|
68 | bool is_freeable : 1;
|
---|
69 |
|
---|
70 | /* Debugging stuff. */
|
---|
71 | int rmutex_locks;
|
---|
72 | fibril_owner_info_t *waits_for;
|
---|
73 | fibril_event_t *sleep_event;
|
---|
74 | };
|
---|
75 |
|
---|
76 | extern fibril_t *fibril_alloc(void);
|
---|
77 | extern void fibril_setup(fibril_t *);
|
---|
78 | extern void fibril_teardown(fibril_t *f);
|
---|
79 | extern fibril_t *fibril_self(void);
|
---|
80 |
|
---|
81 | extern void __fibrils_init(void);
|
---|
82 | extern void __fibrils_fini(void);
|
---|
83 |
|
---|
84 | extern void fibril_wait_for(fibril_event_t *);
|
---|
85 | extern errno_t fibril_wait_timeout(fibril_event_t *, const struct timespec *);
|
---|
86 | extern void fibril_notify(fibril_event_t *);
|
---|
87 |
|
---|
88 | extern errno_t fibril_ipc_wait(ipc_call_t *, const struct timespec *);
|
---|
89 | extern void fibril_ipc_poke(void);
|
---|
90 |
|
---|
91 | /**
|
---|
92 | * "Restricted" fibril mutex.
|
---|
93 | *
|
---|
94 | * Similar to `fibril_mutex_t`, but has a set of restrictions placed on its
|
---|
95 | * use. Within a rmutex critical section, you
|
---|
96 | * - may not use any other synchronization primitive,
|
---|
97 | * save for another `fibril_rmutex_t`. This includes nonblocking
|
---|
98 | * operations like cvar signal and mutex unlock, unless otherwise
|
---|
99 | * specified.
|
---|
100 | * - may not read IPC messages
|
---|
101 | * - may not start a new thread/fibril
|
---|
102 | * (creating fibril without starting is fine)
|
---|
103 | *
|
---|
104 | * Additionally, locking with a timeout is not possible on this mutex,
|
---|
105 | * and there is no associated condition variable type.
|
---|
106 | * This is a design constraint, not a lack of implementation effort.
|
---|
107 | */
|
---|
108 | typedef struct {
|
---|
109 | // TODO: At this point, this is just silly handwaving to hide current
|
---|
110 | // futex use behind a fibril based abstraction. Later, the imple-
|
---|
111 | // mentation will change, but the restrictions placed on this type
|
---|
112 | // will allow it to be simpler and faster than a regular mutex.
|
---|
113 | // There might also be optional debug checking of the assumptions.
|
---|
114 | //
|
---|
115 | // Note that a consequence of the restrictions is that if we are
|
---|
116 | // running on a single thread, no other fibril can ever get to run
|
---|
117 | // while a fibril has a rmutex locked. That means that for
|
---|
118 | // single-threaded programs, we can reduce all rmutex locks and
|
---|
119 | // unlocks to simple branches on a global bool variable.
|
---|
120 |
|
---|
121 | futex_t futex;
|
---|
122 | } fibril_rmutex_t;
|
---|
123 |
|
---|
124 | extern errno_t fibril_rmutex_initialize(fibril_rmutex_t *);
|
---|
125 | extern void fibril_rmutex_destroy(fibril_rmutex_t *);
|
---|
126 | extern void fibril_rmutex_lock(fibril_rmutex_t *);
|
---|
127 | extern bool fibril_rmutex_trylock(fibril_rmutex_t *);
|
---|
128 | extern void fibril_rmutex_unlock(fibril_rmutex_t *);
|
---|
129 |
|
---|
130 | #endif
|
---|