]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/lock.c
Add extra lock debug code but turned off
[bacula/bacula] / bacula / src / stored / lock.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Collection of Bacula Storage daemon locking software
30  *
31  *  Kern Sibbald, 2000-2007.  June 2007
32  *
33  */
34
35 #include "bacula.h"                   /* pull in global headers */
36 #include "stored.h"                   /* pull in Storage Deamon headers */
37
38 #ifdef SD_DEBUG_LOCK
39 const int dbglvl = 0;
40 #else
41 const int dbglvl = 500;
42 #endif
43
44
45 /*
46  *
47  * The Storage daemon has three locking concepts that must be
48  *   understood:
49  *
50  *  1. dblock    blocking the device, which means that the device
51  *               is "marked" in use.  When setting and removing the
52                  block, the device is locked, but after dblock is
53                  called the device is unlocked.
54  *  2. dlock()   simple mutex that locks the device structure. A dlock
55  *               can be acquired while a device is blocked if it is not
56  *               locked.      
57  *  3. r_dlock(locked)  "recursive" dlock, when means that a dlock (mutex)
58  *               will be acquired on the device if it is not blocked
59  *               by some other thread. If the device was blocked by
60  *               the current thread, it will acquire the lock.
61  *               If some other thread has set a block on the device,
62  *               this call will wait until the device is unblocked.
63  *               Can be called with locked true, which means the
64  *               dlock is already set
65  *
66  *  A lock is normally set when modifying the device structure.
67  *  A r_lock is normally acquired when you want to block the device
68  *    i.e. it will wait until the device is not blocked.
69  *  A block is normally set during long operations like writing to
70  *    the device.
71  *  If you are writing the device, you will normally block and 
72  *    lock it.
73  *  A lock cannot be violated. No other thread can touch the
74  *    device while a lock is set.  
75  *  When a block is set, every thread accept the thread that set
76  *    the block will block if r_dlock is called.
77  *  A device can be blocked for multiple reasons, labeling, writing,
78  *    acquiring (opening) the device, waiting for the operator, unmounted,
79  *    ...
80  *  Under certain conditions the block that is set on a device can be    
81  *    stolen and the device can be used by another thread. For example,
82  *    a device is blocked because it is waiting for the operator to  
83  *    mount a tape.  The operator can then unmount the device, and label
84  *    a tape, re-mount it, give back the block, and the job will continue.
85  *
86  *
87  * Functions:
88  *
89  *   DEVICE::dlock()   does P(m_mutex)     (in dev.h)
90  *   DEVICE::dunlock() does V(m_mutex)
91  *
92  *   DEVICE::r_dlock(locked) allows locking the device when this thread
93  *                     already has the device blocked.
94  *                    if (!locked)
95  *                       dlock()
96  *                    if blocked and not same thread that locked
97  *                       pthread_cond_wait
98  *                    leaves device locked 
99  *
100  *   DEVICE::r_dunlock() unlocks but does not unblock
101  *                    same as dunlock();
102  *
103  *   DEVICE::dblock(why)  does 
104  *                    r_dlock();         (recursive device lock)
105  *                    block_device(this, why) 
106  *                    r_dunlock()
107  *
108  *   DEVICE::dunblock does
109  *                    dlock()
110  *                    unblock_device()
111  *                    dunlock()
112  *
113  *   block_device() does  (must be locked and not blocked at entry)  
114  *                    set blocked status
115  *                    set our pid
116  *
117  *   unblock_device() does (must be blocked at entry)
118  *                        (locked on entry)
119  *                        (locked on exit)
120  *                    set unblocked status
121  *                    clear pid
122  *                    if waiting threads
123  *                       pthread_cond_broadcast
124  *
125  *   steal_device_lock() does (must be locked and blocked at entry)
126  *                    save status
127  *                    set new blocked status
128  *                    set new pid
129  *                    unlock()
130  *
131  *   give_back_device_lock() does (must be blocked but not locked)
132  *                    dlock()
133  *                    reset blocked status
134  *                    save previous blocked
135  *                    reset pid
136  *                    if waiting threads
137  *                       pthread_cond_broadcast
138  *
139  */
140
141
142 void DEVICE::dblock(int why)
143 {
144    r_dlock();              /* need recursive lock to block */
145    block_device(this, why);
146    r_dunlock();
147 }
148
149 void DEVICE::dunblock(bool locked)
150 {
151    if (!locked) {
152       dlock();
153    }
154    unblock_device(this);
155    dunlock();
156 }
157
158
159 #ifdef SD_DEBUG_LOCK
160 void DCR::_dlock(const char *file, int line)
161 {
162    dev->_dlock(file, line);
163    m_dev_locked = true;
164 }
165 void DCR::_dunlock(const char *file, int line)
166 {
167    m_dev_locked = false;
168    dev->_dunlock(file, line);
169
170 }
171
172 void DEVICE::_dlock(const char *file, int line)
173 {
174    Dmsg3(sd_dbglvl, "dlock from %s:%d precnt=%d\n", file, line, m_count); 
175    /* Note, this *really* should be protected by a mutex, but
176     *  since it is only debug code we don't worry too much.  
177     */
178    if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
179       Dmsg4(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d\n", 
180             get_jobid_from_tid(m_pid),
181             file, line, m_count);
182    }
183    P(m_mutex);
184    m_pid = pthread_self();
185    m_count++; 
186 }
187
188 void DEVICE::_dunlock(const char *file, int line)
189 {
190    m_count--; 
191    Dmsg3(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d\n", file, line, m_count); 
192    V(m_mutex);   
193 }
194
195 void DEVICE::_r_dunlock(const char *file, int line)
196 {
197    this->_dunlock(file, line);
198 }
199
200 #endif
201
202
203 /*
204  * This is a recursive lock that checks if the device is blocked.
205  *
206  * When blocked is set, all threads EXCEPT thread with id no_wait_id
207  * must wait. The no_wait_id thread is out obtaining a new volume
208  * and preparing the label.
209  */
210 #ifdef SD_DEBUG_LOCK
211 void DEVICE::_r_dlock(const char *file, int line, bool locked)
212 {
213    Dmsg3(sd_dbglvl+1, "r_dlock blked=%s from %s:%d\n", this->print_blocked(),
214          file, line);
215 #else
216 void DEVICE::r_dlock(bool locked)
217 {
218 #endif
219    int stat;
220    if (!locked) {
221       P(m_mutex); /*    this->dlock();   */
222       m_count++;  /*    this->dlock() */
223    }
224    if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
225       this->num_waiting++;             /* indicate that I am waiting */
226       while (this->blocked()) {
227 #ifndef HAVE_WIN32
228          /* thread id on Win32 may be a struct */
229          Dmsg3(sd_dbglvl, "r_dlock blked=%s no_wait=%p me=%p\n", this->print_blocked(),
230                this->no_wait_id, pthread_self());
231 #endif
232          if ((stat = pthread_cond_wait(&this->wait, &m_mutex)) != 0) {
233             berrno be;
234             this->dunlock();
235             Emsg1(M_ABORT, 0, _("pthread_cond_wait failure. ERR=%s\n"),
236                be.bstrerror(stat));
237          }
238       }
239       this->num_waiting--;             /* no longer waiting */
240    }
241 }
242
243 /*
244  * Block all other threads from using the device
245  *  Device must already be locked.  After this call,
246  *  the device is blocked to any thread calling dev->r_lock(),
247  *  but the device is not locked (i.e. no P on device).  Also,
248  *  the current thread can do slip through the dev->r_lock()
249  *  calls without blocking.
250  */
251 void _block_device(const char *file, int line, DEVICE *dev, int state)
252 {
253 // ASSERT(lmgr_mutex_is_locked(&dev->m_mutex) == 1);
254    ASSERT(dev->blocked() == BST_NOT_BLOCKED);
255    dev->set_blocked(state);           /* make other threads wait */
256    dev->no_wait_id = pthread_self();  /* allow us to continue */
257    Dmsg3(sd_dbglvl, "set blocked=%s from %s:%d\n", dev->print_blocked(), file, line);
258 }
259
260 /*
261  * Unblock the device, and wake up anyone who went to sleep.
262  * Enter: device locked
263  * Exit:  device locked
264  */
265 void _unblock_device(const char *file, int line, DEVICE *dev)
266 {
267    Dmsg3(sd_dbglvl, "unblock %s from %s:%d\n", dev->print_blocked(), file, line);
268 // ASSERT(lmgr_mutex_is_locked(&dev->m_mutex) == 1);
269    ASSERT(dev->blocked());
270 // ASSERT(dev->no_wait_id == pthread_self());
271    dev->set_blocked(BST_NOT_BLOCKED);
272    clear_thread_id(dev->no_wait_id);
273    if (dev->num_waiting > 0) {
274       pthread_cond_broadcast(&dev->wait); /* wake them up */
275    }
276 }
277
278 /*
279  * Enter with device locked and blocked
280  * Exit with device unlocked and blocked by us.
281  */
282 void _steal_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state)
283 {
284
285    Dmsg3(sd_dbglvl, "steal lock. old=%s from %s:%d\n", dev->print_blocked(),
286       file, line);
287    hold->dev_blocked = dev->blocked();
288    hold->dev_prev_blocked = dev->dev_prev_blocked;
289    hold->no_wait_id = dev->no_wait_id;
290    dev->set_blocked(state);
291    Dmsg1(sd_dbglvl, "steal lock. new=%s\n", dev->print_blocked());
292    dev->no_wait_id = pthread_self();
293    dev->dunlock();
294 }
295
296 /*
297  * Enter with device blocked by us but not locked
298  * Exit with device locked, and blocked by previous owner
299  */
300 void _give_back_device_lock(const char *file, int line, DEVICE *dev, bsteal_lock_t *hold)
301 {
302    Dmsg3(sd_dbglvl, "return lock. old=%s from %s:%d\n",
303       dev->print_blocked(), file, line);
304    dev->dlock();
305    dev->set_blocked(hold->dev_blocked);
306    dev->dev_prev_blocked = hold->dev_prev_blocked;
307    dev->no_wait_id = hold->no_wait_id;
308    Dmsg1(sd_dbglvl, "return lock. new=%s\n", dev->print_blocked());
309    if (dev->num_waiting > 0) {
310       pthread_cond_broadcast(&dev->wait); /* wake them up */
311    }
312 }
313
314 const char *DEVICE::print_blocked() const 
315 {
316    switch (m_blocked) {
317    case BST_NOT_BLOCKED:
318       return "BST_NOT_BLOCKED";
319    case BST_UNMOUNTED:
320       return "BST_UNMOUNTED";
321    case BST_WAITING_FOR_SYSOP:
322       return "BST_WAITING_FOR_SYSOP";
323    case BST_DOING_ACQUIRE:
324       return "BST_DOING_ACQUIRE";
325    case BST_WRITING_LABEL:
326       return "BST_WRITING_LABEL";
327    case BST_UNMOUNTED_WAITING_FOR_SYSOP:
328       return "BST_UNMOUNTED_WAITING_FOR_SYSOP";
329    case BST_MOUNT:
330       return "BST_MOUNT";
331    case BST_DESPOOLING:
332       return "BST_DESPOOLING";
333    case BST_RELEASING:
334       return "BST_RELEASING";
335    default:
336       return _("unknown blocked code");
337    }
338 }
339
340
341 /*
342  * Check if the device is blocked or not
343  */
344 bool DEVICE::is_device_unmounted()
345 {
346    bool stat;
347    int blk = blocked();
348    stat = (blk == BST_UNMOUNTED) ||
349           (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
350    return stat;
351 }