summaryrefslogtreecommitdiff
path: root/usr/src/lib/libtnfctl/checklib.c
blob: 324cbcfbd13cf5fe2a66d519627e68b92fff8768 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1994, by Sun Microsytems, Inc.
 */

/*
 * Functions to sync up library list with that of the run time linker
 */

#ifndef DEBUG
#define	NDEBUG	1
#endif

#include <assert.h>

#include "tnfctl_int.h"
#include "kernel_int.h"
#include "dbg.h"

tnfctl_errcode_t
tnfctl_check_libs(tnfctl_handle_t *hndl)
{
	tnfctl_errcode_t	prexstat;
	enum event_op_t		dl_evt;
	boolean_t		lmap_ok;

	if (hndl->mode == KERNEL_MODE) {
		prexstat = _tnfctl_refresh_kernel(hndl);
		return (prexstat);
	}

	/* hndl refers to a process */

	/* return value of lmap_ok, dl_evt ignored */
	prexstat = _tnfctl_refresh_process(hndl, &lmap_ok, &dl_evt);
	assert(lmap_ok == B_TRUE);
	return (prexstat);
}

/*
 * _tnfctl_lock_libs() locks the library list maintained in the prex
 * handle against it changing by a dlopen or dlclose.
 *
 * This locking code is between the thread that owns the handle and
 * another thread that may be doing a dlopen/dlclose.  We do not support
 * the situation of having multiple threads operating on the same
 * handle - in effect the code per tnfctl_handle can be thought of as
 * being single-threaded - that is why we can check "hndl->in_objlist"
 * without first obtaining a lock.  "in_objlist" is the re-entrancy
 * protector on the lock i.e. we can call _tnfctl_lock_libs() safely even if
 * this thread has the lock held.  The return value "release_lock" indicates
 * whether the lock should be released or not.  It can be passed into
 * _tnfctl_unlock_libs() which will do the right thing.
 */

tnfctl_errcode_t
_tnfctl_lock_libs(tnfctl_handle_t *hndl, boolean_t *release_lock)
{
	/* this interface is only for INTERNAL_MODE clients */
	assert(hndl->mode == INTERNAL_MODE);

	if (hndl->in_objlist == B_TRUE) {
		/*
		 * already have _tnfctl_lmap_lock held which implies that
		 * the library list has been sync'ed up
		 */
		*release_lock = B_FALSE;
		return (TNFCTL_ERR_NONE);
	}

	/* lock is not currently held, so lock it */
	mutex_lock(&_tnfctl_lmap_lock);
	hndl->in_objlist = B_TRUE;

	*release_lock = B_TRUE;
	return (TNFCTL_ERR_NONE);
}

void
_tnfctl_unlock_libs(tnfctl_handle_t *hndl, boolean_t release_lock)
{
	/* this interface is only for INTERNAL_MODE clients */
	assert(hndl->mode == INTERNAL_MODE);

	if (release_lock) {
		hndl->in_objlist = B_FALSE;
		mutex_unlock(&_tnfctl_lmap_lock);
	}
}

/*
 * _tnfctl_syn_lib_list() syncs up the library list maintained
 * in the prex handle with the libraries in the process (if needed)
 * NOTE: Assumes _tnfctl_lmap_lock is held.
 *
 */
tnfctl_errcode_t
_tnfctl_sync_lib_list(tnfctl_handle_t *hndl)
{
	tnfctl_errcode_t	prexstat = TNFCTL_ERR_NONE;
	enum event_op_t		dl_evt;
	boolean_t		lmap_ok;

	/* this interface is only for INTERNAL_MODE clients */
	assert(hndl->mode == INTERNAL_MODE);

	/* lmap_lock held and in_objlist marked as B_TRUE */
	if (_tnfctl_libs_changed == B_TRUE) {
		prexstat = _tnfctl_refresh_process(hndl, &lmap_ok, &dl_evt);
		if (prexstat) {
			return (prexstat);
		}
	}
	return (TNFCTL_ERR_NONE);
}