1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #pragma once |
40 | |
41 | #include <toku_list.h> |
42 | #include <toku_pthread.h> |
43 | |
44 | extern toku_instr_key *ws_worker_wait_key; |
45 | |
46 | // The work struct is the base class for work to be done by some threads |
47 | struct work { |
48 | struct toku_list next; |
49 | }; |
50 | |
51 | // The workset struct contains the set of work to be done by some threads |
52 | struct workset { |
53 | toku_mutex_t lock; |
54 | struct toku_list worklist; // a list of work |
55 | int refs; // number of workers that have a reference on the workset |
56 | toku_cond_t worker_wait; // a condition variable used to wait for all of the worker to release their reference on the workset |
57 | }; |
58 | |
59 | static inline void workset_init(struct workset *ws) { |
60 | toku_mutex_init(*workset_lock_mutex_key, &ws->lock, nullptr); |
61 | toku_list_init(&ws->worklist); |
62 | ws->refs = 1; // the calling thread gets a reference |
63 | toku_cond_init(*ws_worker_wait_key, &ws->worker_wait, nullptr); |
64 | } |
65 | |
66 | static inline void workset_destroy(struct workset *ws) { |
67 | invariant(toku_list_empty(&ws->worklist)); |
68 | toku_cond_destroy(&ws->worker_wait); |
69 | toku_mutex_destroy(&ws->lock); |
70 | } |
71 | |
72 | static inline void |
73 | workset_lock(struct workset *ws) { |
74 | toku_mutex_lock(&ws->lock); |
75 | } |
76 | |
77 | static inline void |
78 | workset_unlock(struct workset *ws) { |
79 | toku_mutex_unlock(&ws->lock); |
80 | } |
81 | |
82 | // Put work in the workset. Assume the workset is already locked. |
83 | static inline void |
84 | workset_put_locked(struct workset *ws, struct work *w) { |
85 | toku_list_push(&ws->worklist, &w->next); |
86 | } |
87 | |
88 | // Put work in the workset |
89 | static inline void |
90 | workset_put(struct workset *ws, struct work *w) { |
91 | workset_lock(ws); |
92 | workset_put_locked(ws, w); |
93 | workset_unlock(ws); |
94 | } |
95 | |
96 | // Get work from the workset |
97 | static inline struct work * |
98 | workset_get(struct workset *ws) { |
99 | workset_lock(ws); |
100 | struct work *w = NULL; |
101 | if (!toku_list_empty(&ws->worklist)) { |
102 | struct toku_list *l = toku_list_pop_head(&ws->worklist); |
103 | w = toku_list_struct(l, struct work, next); |
104 | } |
105 | workset_unlock(ws); |
106 | return w; |
107 | } |
108 | |
109 | // Add references to the workset |
110 | static inline void |
111 | workset_add_ref(struct workset *ws, int refs) { |
112 | workset_lock(ws); |
113 | ws->refs += refs; |
114 | workset_unlock(ws); |
115 | } |
116 | |
117 | // Release a reference on the workset |
118 | static inline void |
119 | workset_release_ref(struct workset *ws) { |
120 | workset_lock(ws); |
121 | if (--ws->refs == 0) { |
122 | toku_cond_broadcast(&ws->worker_wait); |
123 | } |
124 | workset_unlock(ws); |
125 | } |
126 | |
127 | // Wait until all of the worker threads have released their reference on the workset |
128 | static inline void |
129 | workset_join(struct workset *ws) { |
130 | workset_lock(ws); |
131 | while (ws->refs != 0) { |
132 | toku_cond_wait(&ws->worker_wait, &ws->lock); |
133 | } |
134 | workset_unlock(ws); |
135 | } |
136 | |