File: relinkctl.h

package info (click to toggle)
fis-gtm 6.3-014-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 36,680 kB
  • sloc: ansic: 333,039; asm: 5,180; csh: 4,956; sh: 1,924; awk: 291; makefile: 66; sed: 13
file content (302 lines) | stat: -rw-r--r-- 17,043 bytes parent folder | download | duplicates (2)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/****************************************************************
 *								*
 * Copyright (c) 2013-2020 Fidelity National Information	*
 * Services, Inc. and/or its subsidiaries. All rights reserved.	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#ifndef RELINKCTL_H_INCLUDED
#define RELINKCTL_H_INCLUDED

# include "gtm_limits.h"

/* Input RTNNAME is derived from a file name and we need to convert it to a proper routine name.
 * a) It is possible we got a '_' as the first character in case of a % routine. But the actual routine name stored in
 *	that object file would have '%' as the first character. Fix that along with removing any .m extension
 * b) Also limit routine name length to MAX_MIDENT_LEN (internal design max). Ignore the rest of the file name.
 */
#define	CONVERT_FILENAME_TO_RTNNAME(RTNNAME)					\
MBSTART {									\
	if ('_' == RTNNAME.addr[0])						\
		RTNNAME.addr[0] = '%';						\
	if (!MEMCMP_LIT(&RTNNAME.addr[RTNNAME.len - SIZEOF(DOTM) + 1],DOTM))	\
		RTNNAME.len -= (SIZEOF(DOTM) - 1);				\
	if (MAX_MIDENT_LEN < RTNNAME.len)					\
		RTNNAME.len = MAX_MIDENT_LEN;					\
} MBEND

#define	COMPUTE_RELINKCTL_HASH(RTNNAME, RTNHASH, RELINKCTL_HASH_BUCKETS)	\
{										\
	STR_HASH((RTNNAME)->addr, (RTNNAME)->len, RTNHASH, 0);			\
	RTNHASH = RTNHASH % RELINKCTL_HASH_BUCKETS;				\
}

/* One relinkctl file can contain at most this many # of routines */
#  define	RELINKCTL_MAX_ENTRIES		16000000
#  define	RELINKCTL_MIN_ENTRIES		(WBTEST_ENABLED(WBTEST_RELINKCTL_MAX_ENTRIES) ? 1 : 1000)
#  define	RELINKCTL_DEFAULT_ENTRIES	(WBTEST_ENABLED(WBTEST_RELINKCTL_MAX_ENTRIES) ? 100 : 50000)

#define	RELINKCTL_MMAP_SZ	((size_t)SIZEOF(relinkctl_data))
#define	RELINKSHM_HDR_SIZE	((size_t)SIZEOF(relinkshm_hdr_t))
/* We are guaranteed relinkctl_hash_buckets is an odd prime number and since we want at least 8-byte alignment between different
 * sections of shared memory, we add a 4-byte filler to the RELINKSHM_RTNHASH_SIZE macro computation (that's why we are adding + 1).
 */
#define	RELINKSHM_RTNHASH_SIZE(RELINKCTL_HASH_BUCKETS)	(((size_t)RELINKCTL_HASH_BUCKETS + 1) * SIZEOF(uint4))
#define	RELINKSHM_RECARRAY_SIZE(RELINKCTL_MAX_RTN_ENTRIES)	(((size_t)RELINKCTL_MAX_RTN_ENTRIES) * SIZEOF(relinkrec_t))
#define	RELINKCTL_SHM_SIZE(RELINKCTL_HASH_BUCKETS, RELINKCTL_MAX_RTN_ENTRIES)	(RELINKSHM_HDR_SIZE	\
	+ RELINKSHM_RTNHASH_SIZE(RELINKCTL_HASH_BUCKETS) + RELINKSHM_RECARRAY_SIZE(RELINKCTL_MAX_RTN_ENTRIES))

#define	GET_RELINK_SHM_HDR(LINKCTL)	(relinkshm_hdr_t *)((sm_uc_ptr_t)LINKCTL->shm_hashbase - SIZEOF(relinkshm_hdr_t))

error_def(ERR_RLNKRECLATCH);	/* needed for the RELINKCTL_CYCLE_INCR macro */

/* Macro to bump the cycle# of a given relinkctl record. Make sure shared cycle never becomes 0 after the bump since a process
 * initializes its private cycle to 0 at relinkctl file open time and we want to make sure the private-cycle == shared-cycle
 * check fails always the first time for a process.
 */
#define RELINKCTL_CYCLE_INCR(RELINKREC, LINKCTL)							\
{													\
	if (!grab_latch(&(RELINKREC)->rtnobj_latch, RLNKREC_LATCH_TIMEOUT_SEC, NOT_APPLICABLE, NULL))	\
	{												\
		assert(FALSE);										\
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLNKRECLATCH, 3,				\
			RELINKREC->rtnname_fixed.c, RTS_ERROR_MSTR(&LINKCTL->zro_entry_name));		\
	}												\
	if (0 == ++(RELINKREC)->cycle)									\
		++(RELINKREC)->cycle;									\
	rel_latch(&(RELINKREC)->rtnobj_latch);								\
}

/* A routine buffer is stored a shared memory segment. Since shm sizes are fixed, if ever we cannot fit in a given routine
 * buffer in a given shm, we create another shm with double the size and keep doing this until we come with a shm that can
 * fit in the given routine buffer. We allow for a max of MAX_RTNOBJ_SHM_INDEX such shmids to be allocated per relinkctl file.
 * Since we need 6 bits to represent MAX_RTNOBJ_SHM_INDEX, we treat the array of shmids to be on huge 2**64 sized shmid. Where
 * the top 6 bits represent the index in the shmid array and the remaining 58 bits correspond to the offset within that shmid
 * where the routine buffer can be found. Such an offset into a routine buffer in shared memory is typed as rtnobj_sm_off_t.
 */
#define	RTNOBJ_SHMID_INDEX_MAXBITS	6	/* Max # of bits needed to store NUM_RTNOBJ_SHM_INDEX */
#define	MIN_RTNOBJ_SHM_INDEX	20	/* Minimum size of shared memory segment created to store .o (rtnobj) files is 2**20.
					 * Do not change this macro as gtm_autorelink_shm env var is specified in a multiple of
					 * 2**MIN_RTNOBJ_SHM_INDEX bytes and will have user doc implications.
					 */
#define	MAX_RTNOBJ_SHM_INDEX	58	/* Maximum size of shared memory segment created to store .o (rtnobj) files is 2**57 */
#define NUM_RTNOBJ_SHM_INDEX	(MAX_RTNOBJ_SHM_INDEX - MIN_RTNOBJ_SHM_INDEX)

#define	NULL_RTNOBJ_SM_OFF_T	((sm_off_t)MAXUINT8)	/* Is (2**64 - 1) i.e. 0xFFFF FFFF FFFF FFFF */

#define	RTNOBJ_GET_SHM_INDEX(SHM_OFF)	(SHM_OFF >> MAX_RTNOBJ_SHM_INDEX)
#define	RTNOBJ_GET_SHM_OFFSET(SHM_OFF)	(SHM_OFF & 0x03FFFFFFFFFFFFFFULL)
#define	RTNOBJ_SET_SHM_INDEX_OFF(SHM_INDEX, SHM_OFF)	(((rtnobj_sm_off_t)SHM_INDEX << MAX_RTNOBJ_SHM_INDEX) | (SHM_OFF))

/* For the latch timeouts below, we believe most are likely done within 1 minute but since IO can be done and a failure in one
 * of these locks is a hard-error, the max is set to 4 mins.
 */
#define	RLNKSHM_LATCH_TIMEOUT_SEC	(4 * 60)	/* 4 min */
#define	RLNKREC_LATCH_TIMEOUT_SEC	(4 * 60)	/* 4 min */

#define	MIN_RTNOBJ_SIZE_BITS	8		      /* Minimum object file size (including SIZEOF(rtnobj_hdr_t)) is 2**8 = 256 */
#define	MAX_RTNOBJ_SIZE_BITS	MAX_RTNOBJ_SHM_INDEX  /* Maximum object file size (including SIZEOF(rtnobj_hdr_t)) is 2**32
						       * but when we allocate a rtnobj shared memory segment of size
						       * (2**MAX_RTNOBJ_SHM_INDEX) we want to add that as one element to the
						       * "rtnobjshm_hdr_t->freeList[]" array and hence this definition.
						       */
#define	NUM_RTNOBJ_SIZE_BITS	(MAX_RTNOBJ_SIZE_BITS + 1 - MIN_RTNOBJ_SIZE_BITS)

#define	IS_INSERT		0
#define	IS_DELETE		1

error_def(ERR_REQRLNKCTLRNDWN);	/* needed for the ISSUE_REQRLNKCTLRNDWN_SYSCALL macro */

#define ISSUE_REQRLNKCTLRNDWN_SYSCALL(LINKCTL, ERRSTR, ERRNO)							\
	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13)								\
		ERR_REQRLNKCTLRNDWN, 3, LINKCTL->relinkctl_path, RTS_ERROR_MSTR(&LINKCTL->zro_entry_name), 	\
		ERR_SYSCALL, 5, LEN_AND_STR(ERRSTR), CALLFROM, DEBUG_ONLY(saved_errno = )ERRNO)

#define ISSUE_RELINKCTLERR_SYSCALL(ZRO_ENTRY_NAME, ERRSTR, ERRNO)						\
	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME),		\
		      ERR_SYSCALL, 5, LEN_AND_STR(ERRSTR), CALLFROM, DEBUG_ONLY(saved_errno = )ERRNO)

#define ISSUE_RELINKCTLERR_TEXT(ZRO_ENTRY_NAME, ERRORTEXT, ERRNO)						\
	rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_RELINKCTLERR, 2, RTS_ERROR_MSTR(ZRO_ENTRY_NAME),		\
		      ERR_TEXT, 2, LEN_AND_STR(ERRORTEXT), DEBUG_ONLY(saved_errno = )ERRNO)

typedef	gtm_uint64_t	rtnobj_sm_off_t;

/* Shared structure - relink record corresponding to a relinkctl file (resides in shared memory) */
typedef struct relinkrec_struct
{
	mident_fixed	rtnname_fixed;
	uint4		cycle;
	uint4		hashindex_fl;	/* Forward link ptr to linked list of relinkrec_t structures that have same rtnhash value */
	uint4		numvers;		/* Number of versions of this .o file currently in this relinkctl shared memory */
	uint4		filler_8byte_align;
	gtm_uint64_t	objLen;			/* Total object file length of various versions of this .o file in shared memory */
	gtm_uint64_t	usedLen;		/* Total length used up in shared memory for various versions of this .o file.
						 * Due to rounding up of objLen to nearest 2-power, usedLen >= objLen always.
						 */
	rtnobj_sm_off_t	rtnobj_shm_offset;	/* offset into shared memory where this object file can be found for linking.
						 * If object is not loaded, set to NULL_RTNOBJ_SM_OFF_T.
						 */
	global_latch_t	rtnobj_latch;	/* Lock used to search/insert/delete entries in the
					 * object file linked list (starting at rtnobj_shm_offset)
					 */
	gtm_uint64_t	objhash;	/* Hash of the object file last touched here */
	CACHELINE_PAD_COND(88, 1)	/* Add 40 bytes (on top of 88 bytes) to make this structure 128 bytes to avoid cacheline
					 * interference (between successive relinkrec_t structures in shared memory) on the RS6000
					 * (where the cacheline is 128 bytes currently). Other platforms have smaller
					 * cachelines (i.e. 64 bytes or lesser) and so this structure (88 bytes currently)
					 * taking up more than one cacheline dont require this padding.
					 */
} relinkrec_t;

#define	ZRO_DIR_PATH_MAX	MAX_FN_LEN	/* since "zro_load" which parses $zroutines uses MAX_FN_LEN */

/* Shared structure - relinkctl file header */
typedef struct relinkctl_data_struct
{
	uint4		n_records;
	int4		nattached;	/* Number of processes currently attached. this is approximate, because if a process
					 * is kill 9'd, nattached is not decrememented.
					 * If nattached is 0 upon exiting, we can remove the file.
					 * TODO: Provide fancier cleanup scheme for kill 9. two options:
					 * 	1. SYSV semaphore (as with the db). increment in open_relinkctl
					 * 	2. When we want to cleanup (say mupip routine -rundown), execute 'fuser'
					 */
	int4		relinkctl_shmid;/* ID of primary shared memory segment corresponding to the mmaped relinkctl file.
					 * This contains the array of relinkrec_t structures as well as hash buckets to
					 * speed up search of routine names.
					 */
	uint4		relinkctl_shmlen;/* size of shared memory */
	int4		file_deleted;	/* Way of signaling processes in relinkctl_open about a concurrent delete so they
					 * close their fd and reopen the file.
					 */
	uint4		initialized;	/* relinkctl file has been successfully initialized */
	char		zro_entry_name[ZRO_DIR_PATH_MAX + 1];	/* null-terminated full path of the directory in $zroutines
								 * whose relinkctl file is this. Given a relinkctl file, one can
								 * use this to find the corresponding directory.
								 */
	int		zro_entry_name_len;	/* strlen of the null-terminated "zro_entry_name" */
	int		relinkctl_max_rtn_entries;	/* One relinkctl file can contain at most this many of routines */
	int		relinkctl_hash_buckets;		/* The first prime # above relinkctl_max_rtn_entries */
	pthread_mutex_t	exclu;				/* Protect the file while mmap'd */
} relinkctl_data;

/* Process private structure - describes a relinkctl file. Process private so can be linked into a list in $ZROUTINES order */
typedef struct open_relinkctl_struct
{
	struct open_relinkctl_struct	*next;			/* List of open ctl structures, sorted by zro_entry_name */
	mstr				zro_entry_name;		/* object directory name from $zroutines */
	char				*relinkctl_path;	/* full path of the relinkctl file corresponding to this objdir */
	uint4				n_records;		/* Private copy */
	boolean_t			locked;			/* TRUE if this process owns exclusive lock */
	relinkctl_data			*hdr;			/* Base of mapped file */
	relinkrec_t			*rec_base;
	sm_uint_ptr_t			shm_hashbase;		/* base of hash table in shared memory */
	sm_uc_ptr_t			rtnobj_shm_base[NUM_RTNOBJ_SHM_INDEX];
	int				rtnobj_shmid[NUM_RTNOBJ_SHM_INDEX];
	int				fd;
	int				rtnobj_min_shm_index;	/* Copied over from relinkshm_hdr->rtnobj_min_shm_index */
	int				rtnobj_max_shm_index;	/* Copied over from relinkshm_hdr->rtnobj_max_shm_index */
} open_relinkctl_sgm;

typedef struct rtnobjshm_hdr_struct
{
	que_ent		freeList[NUM_RTNOBJ_SIZE_BITS];
	int		rtnobj_min_free_index;	/* minimum 'i' where freeList[i] has non-zero fl,bl links */
	int		rtnobj_max_free_index;	/* maximum 'i' where freeList[i-1] has non-zero fl,bl links
						 * if no freeList[i] has non-zero fl,bl links, this will be set to  0.
						 */
	int		rtnobj_shmid;
	gtm_uint64_t	real_len;	/* sum of realLen of .o files used currently in this rtnobj shared memory segment */
	gtm_uint64_t	used_len;	/* sum of space occupied by .o files currently in this rtnobj shared memory segment */
	gtm_uint64_t	shm_len;	/* size of shared memory segment */
} rtnobjshm_hdr_t;

/* Shared memory header structure corresponding to relinkctl file. This is followed by a hash-array for speedy routine name
 * access.
 */
typedef struct relinkshm_hdr
{
	char		relinkctl_fname[GTM_PATH_MAX];	/* full path of the relinkctl file (mmr hash is in this name) */
	int		min_shm_index;
	int		rtnobj_min_shm_index;		/* Minimum 'i' where rtnobj_shmhdr[i].rtnobj_shmid is a valid shmid */
	int		rtnobj_max_shm_index;		/* Maximum 'i' where rtnobj_shmhdr[i-1].rtnobj_shmid is a valid shmid.
							 * If no rtnobj_shmhdr[i] has valid shmid, this will be set to 0.
							 */
	boolean_t	rndwn_adjusted_nattch;		/* MUPIP RUNDOWN -RELINKCTL did adjust nattached */
	boolean_t	skip_rundown_check;		/* TRUE if at least one process with gtm_autorelink_keeprtn=1 opened this */
	rtnobjshm_hdr_t	rtnobj_shmhdr[NUM_RTNOBJ_SHM_INDEX];
	/* CACHELINE_PAD macro usages surrounding the actual latch below provides spacing so updates to the latch do not interfere
	 * with updates to adjoining fields which can happen if they fall in the same data cacheline of a processor. No
	 * CACHELINE_PAD before the latch as adjoining fields before the latch are updated only if we hold the latch so no
	 * interference possible.
	 */
	global_latch_t	relinkctl_latch;	/* latch for insertions/deletions of buddy list structurs in any rtnobj shmids */
	CACHELINE_PAD(SIZEOF(global_latch_t), 1)
} relinkshm_hdr_t;

#define	STATE_FREE	0
#define	STATE_ALLOCATED	1

/* "refcnt" is a signed 4-byte integer so the max it can go to is 2**31-1.
 * Once it reaches this value, we can no longer accurately maintain refcnt (rollover issues).
 * So keep it there thereby never removing the corresponding object from shared memory.
 */
#define	REFCNT_INACCURATE	MAXPOSINT4

/* Header structure for each .o file in the "rtnobj" shared memory */
typedef struct rtnobj_hdr_struct
{
	unsigned short	queueIndex;			/* 2**queueIndex is the size of this element (including this header) */
	unsigned char	state;				/* State of this block */
	unsigned char	initialized;			/* Has the .o file been read from disk into this slot */
	int4		refcnt;				/* # of processes that are currently using this .o file */
	gtm_uint64_t	objhash;			/* 8-byte checksum of object file contents.
							 * Used to differentiate multiple versions of the .o file with the same
							 * routine name; Each gets a different routine buffer in shared memory.
							 */
	rtnobj_sm_off_t	next_rtnobj_shm_offset;		/* Offset into shared memory where the routine buffer of the .o file with
							 * the same name as this one can be found but with a different checksum.
							 * Basically a linked list. Null pointer set to NULL_RTNOBJ_SM_OFF_T.
							 */
	uint4		relinkctl_index;		/* Index into reclinkrec_t[] array where the rtnname corresponding to this
							 * .o file can be found; Note multiple versions of .o file with different
							 * <src_cksum_8byte,objLen> values will have different routine buffers in
							 * shared memory each of them pointing back to the same relinkctl_index.
							 */
	uint4		objLen;				/* Size of the allocated .o file. Currently not allowed to go > 4Gb.
							 * <src_cksum_8byte,objLen> together are used to differentiate multiple
							 * versions of the same .o file name; Each of them with a different value
							 * of either src_cksum_8byte or objLen gets a different routine buffer in
							 * shared memory. Note that it is theoretically possible (though rare) that
							 * two different .o files have the same 8-byte src checksum and same objLen.
							 * In that case they will use the same routine buffer. But since we expect
							 * this to be very rare in practice, we consider this acceptable for now.
							 */
	union
	{
		que_ent		freePtr;		/* Pointer to next and previous storage element on free queue */
		unsigned char	userStart;		/* First byte of user useable storage */
	} userStorage;
} rtnobj_hdr_t;

/*
 * Prototypes
 */
open_relinkctl_sgm	*relinkctl_attach(mstr *obj_container_name, mstr *objpath, int objpath_alloc_len);
void			relinkctl_incr_nattached(void);
int			relinkctl_get_key(char key[GTM_PATH_MAX], mstr *zro_entry_name);
relinkrec_t		*relinkctl_find_record(open_relinkctl_sgm *linkctl, mstr *rtnname, uint4 hash, uint4 *prev_hash_index);
relinkrec_t		*relinkctl_insert_record(open_relinkctl_sgm *linkctl, mstr *rtnname);
int			relinkctl_open(open_relinkctl_sgm *linkctl, boolean_t obj_file_missing);
void			relinkctl_init_exclu(open_relinkctl_sgm* linkctl);
void			relinkctl_lock_exclu(open_relinkctl_sgm *linkctl);
void			relinkctl_unlock_exclu(open_relinkctl_sgm *linkctl);
void			relinkctl_rundown(boolean_t decr_attached, boolean_t do_rtnobj_shm_free);

#endif /* RELINKCTL_H_INCLUDED */