VirtualBox

source: kBuild/trunk/src/lib/restartable-syscall-wrappers.c@ 2447

Last change on this file since 2447 was 2447, checked in by bird, 14 years ago

again...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.4 KB
Line 
1/* $Id: restartable-syscall-wrappers.c 2447 2011-07-07 11:59:15Z bird $ */
2/** @file
3 * restartable-syscall-wrappers.c - Workaround for annoying S11 "features".
4 *
5 * The symptoms are that open or mkdir occationally fails with EINTR when
6 * receiving SIGCHLD at the wrong time. With a enough cores, this start
7 * happening on a regular basis.
8 *
9 * The workaround here is to create our own wrappers for these syscalls which
10 * will restart the syscall when appropriate. This depends on the libc
11 * providing alternative names for the syscall entry points.
12 */
13
14/*
15 * Copyright (c) 2011 knut st. osmundsen <[email protected]>
16 *
17 * This file is part of kBuild.
18 *
19 * kBuild is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 3 of the License, or
22 * (at your option) any later version.
23 *
24 * kBuild is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
31 *
32 */
33
34
35/*******************************************************************************
36* Header Files *
37*******************************************************************************/
38#include <sys/types.h>
39#include <sys/stat.h>
40#include <dlfcn.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <stdarg.h>
44#include <stddef.h>
45#include <stdio.h>
46
47
48/*******************************************************************************
49* Defined Constants And Macros *
50*******************************************************************************/
51/** Mangle a syscall name to it's weak alias. */
52#ifdef KBUILD_OS_SOLARIS
53# define WRAP(a_name) _##a_name
54#elif defined(KBUILD_OS_LINUX)
55# define WRAP(a_name) __##a_name
56#else
57# error "Port Me"
58#endif
59
60/** Mangle a syscall name with optional '64' suffix. */
61#if !defined(_LP64) && _FILE_OFFSET_BITS == 64
62# define WRAP64(a_name) WRAP(a_name)##64
63#else
64# define WRAP64(a_name) WRAP(a_name)
65#endif
66
67/** Check whether errno indicates restart. */
68#ifdef ERESTART
69# define SHOULD_RESTART() (errno == EINTR || errno == ERESTART)
70#else
71# define SHOULD_RESTART() (errno == EINTR)
72#endif
73
74/** Used by XSTR. */
75#define XSTR_INNER(x) #x
76/** Returns the expanded argument as a string. */
77#define XSTR(x) XSTR_INNER(x)
78
79
80
81extern int WRAP64(open)(const char *pszName, int fFlags, ...);
82int open(const char *pszName, int fFlags, ...)
83{
84 mode_t fMode;
85 va_list va;
86 int fd;
87
88 va_start(va, fFlags);
89 fMode = va_arg(va, mode_t);
90 va_end(va);
91
92 do
93 fd = WRAP64(open)(pszName, fFlags, fMode);
94 while (fd == -1 && SHOULD_RESTART());
95 return fd;
96}
97
98
99#if !defined(KBUILD_OS_LINUX) /* no wrapper */
100extern int WRAP(mkdir)(const char *pszName, mode_t fMode);
101int mkdir(const char *pszName, mode_t fMode)
102{
103 int rc;
104 do
105 rc = WRAP(mkdir)(pszName, fMode);
106 while (rc == -1 && SHOULD_RESTART());
107 return rc;
108}
109#endif
110
111extern int WRAP64(stat)(const char *pszName, struct stat *pStBuf);
112int stat(const char *pszName, struct stat *pStBuf)
113{
114 int rc;
115 do
116 rc = WRAP64(stat)(pszName, pStBuf);
117 while (rc == -1 && SHOULD_RESTART());
118 return rc;
119}
120
121extern int WRAP64(lstat)(const char *pszName, struct stat *pStBuf);
122int lstat(const char *pszName, struct stat *pStBuf)
123{
124 int rc;
125 do
126 rc = WRAP64(lstat)(pszName, pStBuf);
127 while (rc == -1 && SHOULD_RESTART());
128 return rc;
129}
130
131extern ssize_t WRAP(read)(int fd, void *pvBuf, size_t cbBuf);
132ssize_t read(int fd, void *pvBuf, size_t cbBuf)
133{
134 ssize_t cbRead;
135 do
136 cbRead = WRAP(read)(fd, pvBuf, cbBuf);
137 while (cbRead == -1 && SHOULD_RESTART());
138 return cbRead;
139}
140
141extern ssize_t WRAP(write)(int fd, void *pvBuf, size_t cbBuf);
142ssize_t write(int fd, void *pvBuf, size_t cbBuf)
143{
144 ssize_t cbWritten;
145 do
146 cbWritten = WRAP(write)(fd, pvBuf, cbBuf);
147 while (cbWritten == -1 && SHOULD_RESTART());
148 return cbWritten;
149}
150
151static int dlsym_libc(const char *pszSymbol, void **ppvSym)
152{
153 static void *s_pvLibc = NULL;
154 void *pvLibc;
155 void *pvSym;
156
157 /*
158 * Use the RTLD_NEXT dl feature if present, it's designed for doing
159 * exactly what we want here.
160 */
161#ifdef RTLD_NEXT
162 pvSym = dlsym(RTLD_NEXT, pszSymbol);
163 if (pvSym)
164 {
165 *ppvSym = pvSym;
166 return 0;
167 }
168#endif
169
170 /*
171 * Open libc.
172 */
173 pvLibc = s_pvLibc;
174 if (!pvLibc)
175 {
176#ifdef RTLD_NOLOAD
177 unsigned fFlags = RTLD_NOLOAD | RTLD_NOW;
178#else
179 unsigned fFlags = RTLD_GLOBAL | RTLD_NOW;
180#endif
181#ifdef KBUILD_OS_LINUX
182 pvLibc = dlopen("/lib/libc.so.6", fFlags);
183#else
184 pvLibc = dlopen("/lib/libc.so", fFlags);
185#endif
186 if (!pvLibc)
187 {
188 fprintf(stderr, "restartable-syscall-wrappers: failed to dlopen libc for resolving %s: %s\n",
189 pszSymbol, dlerror());
190 errno = ENOSYS;
191 return -1;
192 }
193 /** @todo check standard symbol? */
194 }
195
196 /*
197 * Resolve the symbol.
198 */
199 pvSym = dlsym(pvLibc, pszSymbol);
200 if (!pvSym)
201 {
202 fprintf(stderr, "restartable-syscall-wrappers: failed to resolve %s: %s\n",
203 pszSymbol, dlerror());
204 errno = ENOSYS;
205 return -1;
206 }
207
208 *ppvSym = pvSym;
209 return 0;
210}
211
212#undef fopen
213FILE *fopen(const char *pszName, const char *pszMode)
214{
215 static union
216 {
217 FILE *(* pfnFOpen)(const char *, const char *);
218 void *pvSym;
219 } s_u;
220 FILE *pFile;
221
222 if ( !s_u.pfnFOpen
223 && dlsym_libc("fopen", &s_u.pvSym) != 0)
224 return NULL;
225
226 do
227 pFile = s_u.pfnFOpen(pszName, pszMode);
228 while (!pFile && SHOULD_RESTART());
229 return pFile;
230}
231
232#undef fopen64
233FILE *fopen64(const char *pszName, const char *pszMode)
234{
235 static union
236 {
237 FILE *(* pfnFOpen64)(const char *, const char *);
238 void *pvSym;
239 } s_u;
240 FILE *pFile;
241
242 if ( !s_u.pfnFOpen64
243 && dlsym_libc("fopen64", &s_u.pvSym) != 0)
244 return NULL;
245
246 do
247 pFile = s_u.pfnFOpen64(pszName, pszMode);
248 while (!pFile && SHOULD_RESTART());
249 return pFile;
250}
251
252/** @todo chmod, chown, chgrp, times, and possible some more. */
253
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette