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