File: offptr.h

package info (click to toggle)
systemtap 5.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 47,556 kB
  • sloc: cpp: 81,117; ansic: 54,933; xml: 49,795; exp: 43,595; sh: 11,526; python: 5,003; perl: 2,252; tcl: 1,312; makefile: 1,006; javascript: 149; lisp: 105; awk: 101; asm: 91; java: 70; sed: 16
file content (134 lines) | stat: -rw-r--r-- 4,788 bytes parent folder | download | duplicates (8)
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
/* pointers based on relative offsets, for shared memory
 * Copyright (C) 2012 Red Hat Inc.
 *
 * This file is part of systemtap, and is free software.  You can
 * redistribute it and/or modify it under the terms of the GNU General
 * Public License (GPL); either version 2, or (at your option) any
 * later version.
 */

#ifndef _OFFPTR_H
#define _OFFPTR_H


/* An offset pointer refers to memory without using an absolute address.  This
 * is useful for shared memory between processes, and perhaps also for cases
 * where memory may move, as with realloc.  */

/* Implementation NB: By nature, NULL is never ever a relative pointer, always
 * absolute.  If it's treated as a plain offset like any other pointer, then it
 * will definitely be wrong when the base is changed.  Thus, NULL must be
 * treated as a special case.  */

/* Here we have a few different implementations for testing and comparison:
 *
 *   OFFPTR_IMPL_GLOBAL: Offsets are stored relative to a global pointer, the
 *   shared-memory base.  This means it will only work for pointers within shm.
 *
 *   OFFPTR_IMPL_SELF: Offsets are stored relative to the offptr_t itself.
 *   This has a little more flexibility, but copying offptr_t values requires
 *   more pointer arithmetic.
 *
 *   OFFPTR_IMPL_POINTERS: Plain pointers, not suitable for use where the
 *   relative functionality is actually needed!  (e.g. anything multiprocess)
 *
 * The default for now is OFFPTR_IMPL_GLOBAL.
 */
#if !defined(OFFPTR_IMPL_GLOBAL) \
	&& !defined(OFFPTR_IMPL_SELF) \
	&& !defined(OFFPTR_IMPL_POINTERS)
#define OFFPTR_IMPL_GLOBAL 1
#endif

#if defined(OFFPTR_IMPL_GLOBAL)
/* OFFPTR_IMPL_GLOBAL: In this mode, the offset is stored relative to the
 * shared-memory base pointer (see runtime/dyninst/shm.c).  This has the
 * advantage of very easy offptr_t copies.  The disadvantage is that it only
 * works for pointers that are part of shared memory.  It may also be costly to
 * dereference the global pointer all the time, but that can be measured.
 *
 * For NULL, we can get away with the special-case of offset 0, so long as we
 * accept that the very base of shared memory is not a valid offptr_t target.
 * Given that, offset 0 should be simpler for code gen, and insulates against
 * bugs slightly since a calloced offptr_t will already represent NULL.
 */

typedef struct {
	/* The offset is always relative to the global shared-memory base.
	 * NULL is special-cased as offset==0.  */
	ptrdiff_t offset;
} offptr_t;

static void* _stp_shm_base; /* from runtime/dyninst/shm.c */

static inline void *
offptr_get(offptr_t* op)
{
	return op->offset ? (_stp_shm_base + op->offset) : NULL;
}

static inline void
offptr_set(offptr_t* op, void* ptr)
{
	op->offset = ptr ? (ptr - _stp_shm_base) : 0;
}

#elif defined(OFFPTR_IMPL_SELF)
/* OFFPTR_IMPL_SELF: In this mode, the offset is stored relative to the
 * offptr_t itself.  The advantage of this is better abstraction, as different
 * offptr_t could refer to different memory blocks (as long as they're
 * self-contained).  The disadvantage is that it requires more math to copy
 * offptr_t values around, as with linked-list updates.
 *
 * For NULL, we could let offset 0 be special, but linked lists often want to
 * link back to themselves, which would be a legitimate offset 0.  Instead,
 * we'll let offset 1 represent NULL, which should never happen naturally as
 * it's in the middle of the offptr_t itself.
 */

typedef struct {
	/* The offset is always relative to the offptr_t itself.
	 * NULL is special-cased as offset==1.  */
	ptrdiff_t offset;
} offptr_t;

static inline void *
offptr_get(offptr_t* op)
{
	return (op->offset == 1) ? NULL : (op->offset + (void*)op);
}

static inline void
offptr_set(offptr_t* op, void* ptr)
{
	op->offset = (ptr == NULL) ? 1 : (ptr - (void*)op);
}

#elif defined(OFFPTR_IMPL_POINTERS)
/* OFFPTR_IMPL_POINTERS: In this mode, offptr_t is basically a plain pointer
 * again.  Despite the level of abstraction, it should compile down to the same
 * as using direct pointers would.
 *
 * Since this is always absolute, the NULL caveat doesn't apply.
 */
typedef struct { void* pointer; } offptr_t;
static inline void * offptr_get(offptr_t* op) { return op->pointer; }
static inline void offptr_set(offptr_t* op, void* ptr) { op->pointer = ptr; }

#else
#error "No offptr_t implementation?!"
#endif


/* Since offptr_t is untyped, this template-like macro lets you define
 * accessors with the appropriate pointer types enforced.  */
#define DEFINE_OFFPTR_GETSET(prefix, T1, T2, member)			\
	static inline T2* prefix##_##member(T1* ptr) {			\
		return (T2*) offptr_get(&ptr->member);			\
	}								\
	static inline void prefix##_set_##member(T1* ptr, T2* val) {	\
		offptr_set(&ptr->member, val);				\
	}


#endif /* _OFFPTR_H */