pastebin - collaborative debugging tool
rovema.kpaste.net RSS

Difference between
modified post 0c6 by Anonymous on Tue 28th Mar 2023 14:49
original post 06f04 by Anonymous on Wed 30th Nov 2022 14:50
Download diff
Show old version | new version | both versions

    
11
22
/*
33
 * linux_vdso_my_sched_getcpu.c - use Linux VDSO
44
 * shortcut for |sched_getcpu()|, even if userland (g)libc
55
 * does not have support for VDSO
66
 *
77
 * Compile with:
88
 * $ clang -std=c99 -g -m32 -Wall \
99
 * 	-Wextra linux_vdso_my_sched_getcpu.c -lpthread \
1010
 *	-o linux_vdso_my_sched_getcpu
1111
 *
1212
 * Written by Roland Mainz <roland.mainz@nrubsig.org>
1313
 *
1414
 */
1515
1616
#define _XOPEN_SOURCE	700
1717
#define _GNU_SOURCE	1
1818
1919
#include <stdio.h>
2020
#include <stddef.h>
2121
#include <stdlib.h>
2222
#include <string.h>
2323
#include <elf.h>
2424
#include <time.h>
2525
#include <pthread.h>
2626
#include <sched.h>
27+
#include <unistd.h>
2728
#include <sys/auxv.h>
29+
#include <sys/syscall.h>
2830
2931
/* Catch cursed idiots playing around with XPG config */
3032
#if (_XOPEN_SOURCE < 600)
3133
#error _XOPEN_SOURCE wrong version
3234
#endif
3335
3436
/* Build test code ? */
3537
#define MY_SCHED_GETCPU_TESTS 1
3638
3739
/* debug */
3840
#if 1
3941
#define D(x) x
4042
#else
4143
#define D(x)
4244
#endif
4345
4446
4547
/* 32bit vs. 64bit */
46-
#if (__PTRDIFF_WIDTH__ == 32)
48+
#if (__SIZEOF_PTRDIFF_T__ == 4)
4749
typedef Elf32_Ehdr	ElfXX_Ehdr;
4850
typedef Elf32_Shdr	ElfXX_Shdr;
4951
typedef Elf32_Sym	ElfXX_Sym;
50-
#elif (__PTRDIFF_WIDTH__ == 64)
52+
#elif (__SIZEOF_PTRDIFF_T__ == 8)
5153
typedef Elf64_Ehdr	ElfXX_Ehdr;
5254
typedef Elf64_Shdr	ElfXX_Shdr;
5355
typedef Elf64_Sym	ElfXX_Sym;
5456
#else
55-
#error Unsupported __PTRDIFF_WIDTH__
57+
#error Unsupported __SIZEOF_PTRDIFF_T__
5658
#endif
5759
5860
5961
/*
6062
 * |get_linux_vdso_sym()| - Look up symbol in AUX AT_SYSINFO_EHDR
6163
 */
6264
static
6365
void *get_linux_vdso_sym(const char *funcname)
6466
{
6567
	const char	*dynstr;
6668
	void		*ret = NULL;
6769
	unsigned char	*vdso_addr;
6870
	ssize_t		i;
6971
	size_t		si;
7072
	const char	*name;
7173
	ElfXX_Ehdr	*elf_header;
7274
	ElfXX_Shdr	*section_header;
7375
	ElfXX_Shdr	*s;
7476
	ElfXX_Shdr	*s2;
7577
	ElfXX_Sym	*sym;
7678
7779
	/*
7880
	 * valgrind can disable |AT_SYSINFO_EHDR| - see
7981
	 * https://www.mail-archive.com/kde-bugs-dist@kde.org/msg550927.html
8082
	 */
8183
	vdso_addr = (unsigned char *)getauxval(AT_SYSINFO_EHDR);
8284
	if (!vdso_addr) {
8385
		D((void)fprintf(stderr,
8486
			"get_linux_vdso_sym: getauxval(AT_SYSINFO_EHDR) failed.\n"));
8587
		return NULL;
8688
	}
8789
8890
	elf_header = (ElfXX_Ehdr *)vdso_addr;
8991
	section_header = (ElfXX_Shdr *)(vdso_addr + elf_header->e_shoff);
9092
9193
	for (dynstr = NULL, i=0L; i < elf_header->e_shnum; i++) {
9294
		s    = &section_header[i];
9395
		s2   = &section_header[elf_header->e_shstrndx];
9496
		name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name);
9597
9698
		if (strcmp(name, ".dynstr") == 0) {
9799
			dynstr = (const char *)(vdso_addr + s->sh_offset);
98100
			break;
99101
		}
100102
	}
101103
102104
	if (!dynstr)
103105
		return NULL;
104106
105107
	for (i=0L; i < elf_header->e_shnum; i++) {
106108
		s    = &section_header[i];
107109
		s2   = &section_header[elf_header->e_shstrndx];
108110
		name = (const char*)(vdso_addr + s2->sh_offset + s->sh_name);
109111
110112
		/* Not .dynsym ? Then look at next section... */
111113
		if (strcmp(name, ".dynsym"))
112114
			continue;
113115
114116
		for (si=0L; si < (s->sh_size/s->sh_entsize); si++) {
115117
			sym = &(((ElfXX_Sym*)(vdso_addr + s->sh_offset))[si]);
116118
			name = dynstr + sym->st_name;
117119
118120
			D((void)fprintf(stderr, "get_linux_vdso_sym: "
119121
				"symbol=|%s| vs. |%s|\n",
120122
				funcname, name));
121123
			if (!strcmp(name, funcname)) {
122124
				ret = (void *)(vdso_addr + sym->st_value);
123125
				break;
124126
			}
125127
		}
126128
127129
		if (ret)
128130
			break;
129131
	}
130132
131133
	return ret;
132134
}
133135
134136
135137
/*
136138
 * Initalisation code
137139
 */
138140
139141
/*
140142
 * Note that the |getcpu()| prototype here differs between
141143
 * Linux versions, the third argument (|tcache|) has been
142144
 * removed, and the prototype was moved from
143145
 * <linux/getcpu.h> to <bits/sched.h>.
144146
 */
145147
typedef int (getcpu_func_t)(unsigned *cpu, unsigned *node, void *tcache);
146148
147149
static pthread_once_t my_getcpu_func_is_initialized = PTHREAD_ONCE_INIT;
148150
static getcpu_func_t *my_getcpu_func = NULL;
149151
150152
151153
static
152154
void my_getcpu_func_init(void)
153155
{
154156
	my_getcpu_func = (getcpu_func_t *)get_linux_vdso_sym("__vdso_getcpu");
155157
	if (!my_getcpu_func)
156158
		my_getcpu_func = (getcpu_func_t *)get_linux_vdso_sym("getcpu");
157159
158160
	D((void)fprintf(stderr, "my_getcpu_func_init: "
159161
		"my_getcpu_func = 0x%lx (%s)\n",
160162
		(long)my_getcpu_func,
161163
		(my_getcpu_func?
162164
			"Using fast codepath":
163165
			"Using slow codepath")));
164166
	if (!my_getcpu_func) {
165167
		(void)fprintf(stderr, "my_getcpu_func_init: "
166168
			"WARNING: aux symbol for getcpu not found"
167169
			", using slow libc codepath.\n");
168170
	}
169171
}
170172
171173
172174
/*
173175
 * |my_sched_getcpu()| - our "public" interface
174176
 *
175177
 * Notes:
176178
 * - The first call might be slower because the call to
177179
 * |my_getcpu_func_init()|
178180
 */
179181
int my_sched_getcpu(void)
180182
{
181183
	unsigned int	cpu;
182184
	int		s;
183185
184186
	(void)pthread_once(&my_getcpu_func_is_initialized,
185187
		my_getcpu_func_init);
186188
187189
	if (my_getcpu_func) {
188190
		/* our MY_getcpu_TESTS own "fast" codepath */
189191
		s = (*my_getcpu_func)(&cpu, NULL, NULL);
190192
	}
191193
	else
192194
	{
195+
#define FORCE_GETCPU_SYSCALL 1
193199
		/*
194200
		 * libc codepath, whatever they use - might be VDSO,
195201
		 * might be syscall
196202
		 *
197203
		 * Note that the prototype here differs between Linux
198204
		 * versions, the third argument (|tcache|) has been
199205
		 * removed, and the prototype was moved from
200206
		 * <linux/getcpu.h> to <bits/sched.h>.
201207
		 * Depending on glibc version this might cause
202208
		 * crashes.
203209
		 */
204210
		s = getcpu(&cpu, NULL/*, NULL*/);
211+
#endif /* defined(SYS_getcpu) && FORCE_GETCPU_SYSCALL */
205212
	}
206213
207214
	if (s == -1)
208215
		return -1;
209216
210217
	return (int)cpu;
211218
}
212219
213220
214221
#ifdef MY_SCHED_GETCPU_TESTS
215222
/*
216223
 * test code
217224
 */
218225
static
219226
void test_my_sched_getcpu1(void)
220227
{
221228
	int cpu_num;
222229
223230
	cpu_num = my_sched_getcpu();
224231
	(void)printf("my_sched_getcpu() = %d\n", cpu_num);
225232
226233
	cpu_num = sched_getcpu();
227234
	(void)printf("sched_getcpu()    = %d\n", cpu_num);
228235
}
229236
230237
231238
int main(int ac, char *av[])
232239
{
233240
	(void)ac;
234241
	(void)av;
235242
236243
	test_my_sched_getcpu1();
237244
238245
	return EXIT_SUCCESS;
239246
}
240247
241248
#endif /* MY_SCHED_GETCPU_TESTS */
242249

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at