/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- dlopen
- dlclose
1 /****************************************************************************
2 * Copyright (C) 2006-2013 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3 * jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu *
4 * *
5 * This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src). *
6 * *
7 * DMTCP:dmtcp/src is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP:dmtcp/src is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include "dmtcp.h"
25
26 #define _real_dlopen NEXT_FNC(dlopen)
27 #define _real_dlclose NEXT_FNC(dlclose)
28
29 extern "C" int dmtcp_libdlLockLock();
30 extern "C" void dmtcp_libdlLockUnlock();
31
32 /* Reason for using thread_performing_dlopen_dlsym:
33 *
34 * dlsym/dlopen/dlclose make a call to calloc() internally. We do not want to
35 * checkpoint while we are in the midst of dlopen etc. as it can lead to
36 * undesired behavior. To do so, we use WRAPPER_EXECUTION_DISABLE_CKPT() at the
37 * beginning of the funtion. However, if a checkpoint request is received right
38 * after WRAPPER_EXECUTION_DISABLE_CKPT(), the ckpt-thread is queued for wrlock
39 * on the pthread-rwlock and any subsequent request for rdlock by other threads
40 * will have to wait until the ckpt-thread releases the lock. However, in this
41 * scenario, dlopen calls calloc, which then calls
42 * WRAPPER_EXECUTION_DISABLE_CKPT() and hence resulting in a deadlock.
43 *
44 * We set this variable to true, once we are inside the dlopen/dlsym/dlerror
45 * wrapper, so that the calling thread won't try to acquire the lock later on.
46 *
47 * EDIT: Instead of acquiring wrapperExecutionLock, we acquire libdlLock.
48 * libdlLock is a higher priority lock than wrapperExectionLock i.e. during
49 * checkpointing this lock is acquired before wrapperExecutionLock by the
50 * ckpt-thread.
51 * Rationale behind not using wrapperExecutionLock and creating an extra lock:
52 * When loading a shared library, dlopen will initialize the static objects
53 * in the shared library by calling their corresponding constructors.
54 * Further, the constructor might call fork/exec to create new
55 * process/program. Finally, fork/exec require the wrapperExecutionLock in
56 * exclusive mode (writer lock). However, if dlopen wrapper acquires the
57 * wrapperExecutionLock, the fork wrapper will deadlock when trying to get
58 * writer lock.
59 *
60 * EDIT: The dlopen() wrappers causes the problems with the semantics of RPATH
61 * associated with the caller library. In future, we can work without this
62 * plugin by detecting if we are in the middle of a dlopen by looking up the
63 * stack frames.
64 */
65
66 extern "C"
67 void *dlopen(const char *filename, int flag)
68 {
69 bool lockAcquired = dmtcp_libdlLockLock();
70 void *ret = _real_dlopen(filename, flag);
71 if (lockAcquired) {
72 dmtcp_libdlLockUnlock();
73 }
74 return ret;
75 }
76
77 extern "C"
78 int dlclose(void *handle)
79 {
80 bool lockAcquired = dmtcp_libdlLockLock();
81 int ret = _real_dlclose(handle);
82 if (lockAcquired) {
83 dmtcp_libdlLockUnlock();
84 }
85 return ret;
86 }
87