VirtualBox

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

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

solaris fopen hack.

  • 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 2449 2011-07-07 12:05:30Z 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 <bird-kBuild-spamx@anduin.net>
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#ifdef KBUILD_OS_SOLARIS
46# undef __PRAGMA_REDEFINE_EXTNAME
47#endif
48#include <stdio.h>
49
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54/** Mangle a syscall name to it's weak alias. */
55#ifdef KBUILD_OS_SOLARIS
56# define WRAP(a_name) _##a_name
57#elif defined(KBUILD_OS_LINUX)
58# define WRAP(a_name) __##a_name
59#else
60# error "Port Me"
61#endif
62
63/** Mangle a syscall name with optional '64' suffix. */
64#if !defined(_LP64) && _FILE_OFFSET_BITS == 64
65# define WRAP64(a_name) WRAP(a_name)##64
66#else
67# define WRAP64(a_name) WRAP(a_name)
68#endif
69
70/** Check whether errno indicates restart. */
71#ifdef ERESTART
72# define SHOULD_RESTART() (errno == EINTR || errno == ERESTART)
73#else
74# define SHOULD_RESTART() (errno == EINTR)
75#endif
76
77/** Used by XSTR. */
78#define XSTR_INNER(x) #x
79/** Returns the expanded argument as a string. */
80#define XSTR(x) XSTR_INNER(x)
81
82
83
84extern int WRAP64(open)(const char *pszName, int fFlags, ...);
85int open(const char *pszName, int fFlags, ...)
86{
87 mode_t fMode;
88 va_list va;
89 int fd;
90
91 va_start(va, fFlags);
92 fMode = va_arg(va, mode_t);
93 va_end(va);
94
95 do
96 fd = WRAP64(open)(pszName, fFlags, fMode);
97 while (fd == -1 && SHOULD_RESTART());
98 return fd;
99}
100
101
102#if !defined(KBUILD_OS_LINUX) /* no wrapper */
103extern int WRAP(mkdir)(const char *pszName, mode_t fMode);
104int mkdir(const char *pszName, mode_t fMode)
105{
106 int rc;
107 do
108 rc = WRAP(mkdir)(pszName, fMode);
109 while (rc == -1 && SHOULD_RESTART());
110 return rc;
111}
112#endif
113
114extern int WRAP64(stat)(const char *pszName, struct stat *pStBuf);
115int stat(const char *pszName, struct stat *pStBuf)
116{
117 int rc;
118 do
119 rc = WRAP64(stat)(pszName, pStBuf);
120 while (rc == -1 && SHOULD_RESTART());
121 return rc;
122}
123
124extern int WRAP64(lstat)(const char *pszName, struct stat *pStBuf);
125int lstat(const char *pszName, struct stat *pStBuf)
126{
127 int rc;
128 do
129 rc = WRAP64(lstat)(pszName, pStBuf);
130 while (rc == -1 && SHOULD_RESTART());
131 return rc;
132}
133
134extern ssize_t WRAP(read)(int fd, void *pvBuf, size_t cbBuf);
135ssize_t read(int fd, void *pvBuf, size_t cbBuf)
136{
137 ssize_t cbRead;
138 do
139 cbRead = WRAP(read)(fd, pvBuf, cbBuf);
140 while (cbRead == -1 && SHOULD_RESTART());
141 return cbRead;
142}
143
144extern ssize_t WRAP(write)(int fd, void *pvBuf, size_t cbBuf);
145ssize_t write(int fd, void *pvBuf, size_t cbBuf)
146{
147 ssize_t cbWritten;
148 do
149 cbWritten = WRAP(write)(fd, pvBuf, cbBuf);
150 while (cbWritten == -1 && SHOULD_RESTART());
151 return cbWritten;
152}
153
154static int dlsym_libc(const char *pszSymbol, void **ppvSym)
155{
156 static void *s_pvLibc = NULL;
157 void *pvLibc;
158 void *pvSym;
159
160 /*
161 * Use the RTLD_NEXT dl feature if present, it's designed for doing
162 * exactly what we want here.
163 */
164#ifdef RTLD_NEXT
165 pvSym = dlsym(RTLD_NEXT, pszSymbol);
166 if (pvSym)
167 {
168 *ppvSym = pvSym;
169 return 0;
170 }
171#endif
172
173 /*
174 * Open libc.
175 */
176 pvLibc = s_pvLibc;
177 if (!pvLibc)
178 {
179#ifdef RTLD_NOLOAD
180 unsigned fFlags = RTLD_NOLOAD | RTLD_NOW;
181#else
182 unsigned fFlags = RTLD_GLOBAL | RTLD_NOW;
183#endif
184#ifdef KBUILD_OS_LINUX
185 pvLibc = dlopen("/lib/libc.so.6", fFlags);
186#else
187 pvLibc = dlopen("/lib/libc.so", fFlags);
188#endif
189 if (!pvLibc)
190 {
191 fprintf(stderr, "restartable-syscall-wrappers: failed to dlopen libc for resolving %s: %s\n",
192 pszSymbol, dlerror());
193 errno = ENOSYS;
194 return -1;
195 }
196 /** @todo check standard symbol? */
197 }
198
199 /*
200 * Resolve the symbol.
201 */
202 pvSym = dlsym(pvLibc, pszSymbol);
203 if (!pvSym)
204 {
205 fprintf(stderr, "restartable-syscall-wrappers: failed to resolve %s: %s\n",
206 pszSymbol, dlerror());
207 errno = ENOSYS;
208 return -1;
209 }
210
211 *ppvSym = pvSym;
212 return 0;
213}
214
215#undef fopen
216FILE *fopen(const char *pszName, const char *pszMode)
217{
218 static union
219 {
220 FILE *(* pfnFOpen)(const char *, const char *);
221 void *pvSym;
222 } s_u;
223 FILE *pFile;
224
225 if ( !s_u.pfnFOpen
226 && dlsym_libc("fopen", &s_u.pvSym) != 0)
227 return NULL;
228
229 do
230 pFile = s_u.pfnFOpen(pszName, pszMode);
231 while (!pFile && SHOULD_RESTART());
232 return pFile;
233}
234
235#undef fopen64
236FILE *fopen64(const char *pszName, const char *pszMode)
237{
238 static union
239 {
240 FILE *(* pfnFOpen64)(const char *, const char *);
241 void *pvSym;
242 } s_u;
243 FILE *pFile;
244
245 if ( !s_u.pfnFOpen64
246 && dlsym_libc("fopen64", &s_u.pvSym) != 0)
247 return NULL;
248
249 do
250 pFile = s_u.pfnFOpen64(pszName, pszMode);
251 while (!pFile && SHOULD_RESTART());
252 return pFile;
253}
254
255/** @todo chmod, chown, chgrp, times, and possible some more. */
256
Note: See TracBrowser for help on using the repository browser.

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