With a small typo pointed out by Bjoern, and fixing at least the
prototypes for the socket v.s. file implementations of inherit, here
is the revised patch. It is 'theoretical' - I'll vet it on OS/X in
the morning.
I have one question; should we also be toggling sockets as
FD_CLOEXEC? Common sense tells me, yes - we should
set that flag by default in all the assignments scattered
throughout network_io/unix/sockets.c.
Enjoy the patch... comments greatly appreciated. It's a little
to quiet on this issue... and your *win32* hacker is coding the
Unix solution. Are you scared yet :-?
Bill
A: well, at least you should be...
? consider_accept_retry.patch
? foo
Index: file_io/os2/filedup.c
===================================================================
RCS file: /home/cvs/apr/file_io/os2/filedup.c,v
retrieving revision 1.32
diff -u -r1.32 filedup.c
--- file_io/os2/filedup.c 7 Jan 2003 00:52:51 -0000 1.32
+++ file_io/os2/filedup.c 18 Mar 2003 05:38:40 -0000
@@ -92,7 +92,8 @@
if (*new_file == NULL) {
apr_pool_cleanup_register(dup_file->pool, dup_file, apr_file_cleanup,
- apr_pool_cleanup_null);
+ (dup_file->flags & APR_INHERIT)
+ ? apr_pool_cleanup_null : apr_file_cleanup);
*new_file = dup_file;
}
Index: file_io/os2/open.c
===================================================================
RCS file: /home/cvs/apr/file_io/os2/open.c,v
retrieving revision 1.59
diff -u -r1.59 open.c
--- file_io/os2/open.c 2 Mar 2003 03:11:22 -0000 1.59
+++ file_io/os2/open.c 18 Mar 2003 05:38:40 -0000
@@ -67,7 +67,6 @@
}
-
APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname,
apr_int32_t flag, apr_fileperms_t perm, apr_pool_t *pool)
{
int oflags = 0;
Index: file_io/unix/filedup.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/filedup.c,v
retrieving revision 1.53
diff -u -r1.53 filedup.c
--- file_io/unix/filedup.c 7 Jan 2003 00:52:53 -0000 1.53
+++ file_io/unix/filedup.c 18 Mar 2003 05:38:40 -0000
@@ -64,28 +64,29 @@
{
int rv;
- if ((*new_file) == NULL) {
- if (which_dup == 1) {
- (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
- if ((*new_file) == NULL) {
- return APR_ENOMEM;
- }
- (*new_file)->pool = p;
- } else {
- /* We can't dup2 unless we have a valid new_file */
+ if (which_dup == 2) {
+ if (*new_file == NULL) {
return APR_EINVAL;
}
- }
-
- if (which_dup == 2) {
+ apr_pool_cleanup_kill((*new_file)->pool, *new_file,
+ apr_unix_file_cleanup);
rv = dup2(old_file->filedes, (*new_file)->filedes);
} else {
- rv = ((*new_file)->filedes = dup(old_file->filedes));
+ rv = dup(old_file->filedes);
}
if (rv == -1)
return errno;
-
+
+ if ((*new_file) == NULL) {
+ (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
+ (*new_file)->pool = p;
+ }
+
+ if (which_dup != 2) {
+ (*new_file)->filedes = rv;
+ }
+
(*new_file)->fname = apr_pstrdup(p, old_file->fname);
(*new_file)->buffered = old_file->buffered;
@@ -112,10 +113,38 @@
/* make sure unget behavior is consistent */
(*new_file)->ungetchar = old_file->ungetchar;
- /* apr_file_dup() clears the inherit attribute, user must call
- * apr_file_inherit_set() again on the dupped handle, as necessary.
+ /* apr_file_dup() clears the inherit attribute except for fd's 0..2
+ * so the user must call apr_file_inherit_set() again on the dupped
+ * handle, when desired.
*/
- (*new_file)->flags = old_file->flags & ~APR_INHERIT;
+ if ((*new_file)->filedes <= 2) {
+ /* Default the stdin/out/err fd's to inherited */
+ (*new_file)->flags = old_file->flags | APR_INHERIT;
+ }
+ else {
+ (*new_file)->flags = old_file->flags & ~APR_INHERIT;
+ }
+
+ /* we do this here as we don't want to double register an existing
+ * apr_file_t for cleanup
+ */
+ apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
+ apr_unix_file_cleanup,
+ (old_file->flags & APR_INHERIT)
+ ? apr_pool_cleanup_null
+ : apr_unix_file_cleanup);
+
+#ifdef FD_CLOEXEC
+ int ffd = fcntl((*new_file)->filedes, F_GETFD, 0);
+ if ((ffd >= 0) && (old_file->flags & APR_INHERIT)) {
+ ffd = fcntl((*new_file)->filedes, F_SETFD, ffd | FD_CLOEXEC);
+ }
+ /* if (ffd < 0)
+ * XXX: What to do in this case? No good ideas.
+ * returning an error implies we have to go
+ * back and close the original handle.
+ */
+#endif
return APR_SUCCESS;
}
@@ -123,25 +152,19 @@
APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
apr_file_t *old_file, apr_pool_t *p)
{
- apr_status_t rv;
-
- rv = _file_dup(new_file, old_file, p, 1);
- if (rv != APR_SUCCESS)
- return rv;
-
- /* we do this here as we don't want to double register an existing
- * apr_file_t for cleanup
- */
- apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
- apr_unix_file_cleanup, apr_unix_file_cleanup);
- return rv;
-
+ return _file_dup(new_file, old_file, p, 1);
}
APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
apr_file_t *old_file, apr_pool_t *p)
{
#ifdef NETWARE
+ /* XXX Netware must special-case any dup2(stdin/out/err,...)
+ * as provided by apr_file_open_std[in|out|err].
+ * At least we pre-close the target file...
+ */
+ apr_pool_cleanup_run(new_file->pool, new_file,
+ apr_unix_file_cleanup);
return _file_dup(&new_file, old_file, p, 1);
#else
return _file_dup(&new_file, old_file, p, 2);
@@ -177,7 +200,9 @@
if (!(old_file->flags & APR_FILE_NOCLEANUP)) {
apr_pool_cleanup_register(p, (void *)(*new_file),
apr_unix_file_cleanup,
- apr_unix_file_cleanup);
+ ((*new_file)->flags & APR_INHERIT)
+ ? apr_pool_cleanup_null
+ : apr_unix_file_cleanup);
}
old_file->filedes = -1;
Index: file_io/unix/mktemp.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/mktemp.c,v
retrieving revision 1.27
diff -u -r1.27 mktemp.c
--- file_io/unix/mktemp.c 7 Jan 2003 00:52:53 -0000 1.27
+++ file_io/unix/mktemp.c 18 Mar 2003 05:38:40 -0000
@@ -225,6 +225,13 @@
if (fd == -1) {
return errno;
}
+ /* XXX: We must reset several flags values as passed-in, since
+ * mkstemp didn't subscribe to our preference flags.
+ *
+ * We either have to unset the flags, or fix up the fd and other
+ * xthread and inherit bits appropriately. Since gettemp() above
+ * calls apr_file_open, our flags are respected in that code path.
+ */
apr_os_file_put(fp, &fd, flags, p);
(*fp)->fname = apr_pstrdup(p, template);
Index: file_io/unix/open.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/open.c,v
retrieving revision 1.110
diff -u -r1.110 open.c
--- file_io/unix/open.c 6 Mar 2003 09:24:17 -0000 1.110
+++ file_io/unix/open.c 18 Mar 2003 05:38:40 -0000
@@ -149,11 +149,33 @@
#endif
if (perm == APR_OS_DEFAULT) {
- fd = open(fname, oflags, 0666);
+ perm = 0x666;
}
- else {
- fd = open(fname, oflags, apr_unix_perms2mode(perm));
- }
+
+ fd = open(fname, oflags, apr_unix_perms2mode(perm));
+
+#ifdef FD_CLOEXEC
+ /* If we are registering a cleanup - we match the FD_CLOEXEC
+ * state to our cleanup state. - meaning that either flags
+ * APR_FILE_NOCLEANUP or APR_INHERIT will inhibit CLOEXEC.
+ */
+ if (fd >= 0 && !(flag & APR_FILE_NOCLEANUP | APR_INHERIT)) {
+ /* XXX: in multithreaded applications, there is a race
+ * between open() above and setting the FD_CLOEXEC bit.
+ */
+ int ffd = fcntl(fd, F_GETFD, 0);
+ if (ffd >= 0) {
+ ffd = fcntl(fd, F_SETFD, ffd | FD_CLOEXEC);
+ }
+ if (ffd < 0) {
+ /* XXX: What to do in this case? No good ideas; one option:
+ * close(fd);
+ * fd = -1;
+ */
+ }
+ }
+#endif
+
if (fd < 0) {
return errno;
}
@@ -191,7 +213,10 @@
if (!(flag & APR_FILE_NOCLEANUP)) {
apr_pool_cleanup_register((*new)->pool, (void *)(*new),
- apr_unix_file_cleanup,
apr_unix_file_cleanup);
+ apr_unix_file_cleanup,
+ (flag & APR_INHERIT)
+ ? apr_pool_cleanup_null
+ : apr_unix_file_cleanup);
}
return APR_SUCCESS;
}
@@ -292,8 +317,8 @@
return apr_os_file_put(thefile, &fd, 0, pool);
}
-APR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup)
+APR_IMPLEMENT_INHERIT_SET(file, flags, filedes, pool, apr_unix_file_cleanup)
-APR_IMPLEMENT_INHERIT_UNSET(file, flags, pool, apr_unix_file_cleanup)
+APR_IMPLEMENT_INHERIT_UNSET(file, flags, filedes, pool, apr_unix_file_cleanup)
APR_POOL_IMPLEMENT_ACCESSOR(file)
Index: include/arch/unix/apr_arch_inherit.h
===================================================================
RCS file: /home/cvs/apr/include/arch/unix/apr_arch_inherit.h,v
retrieving revision 1.1
diff -u -r1.1 apr_arch_inherit.h
--- include/arch/unix/apr_arch_inherit.h 6 Jan 2003 23:44:26 -0000
1.1
+++ include/arch/unix/apr_arch_inherit.h 18 Mar 2003 05:38:41 -0000
@@ -59,7 +59,47 @@
#define APR_INHERIT (1 << 24) /* Must not conflict with other bits */
-#define APR_IMPLEMENT_INHERIT_SET(name, flag, pool, cleanup) \
+#ifdef FD_CLOEXEC
+
+#define APR_IMPLEMENT_INHERIT_SET(name, flag, fd, pool, cleanup) \
+apr_status_t apr_##name##_inherit_set(apr_##name##_t *the##name) \
+{ \
+ if (!(the##name->flag & APR_INHERIT)) { \
+ int ffd = fcntl(the##name->fd, F_GETFD, 0); \
+ if (ffd >= 0) \
+ ffd = fcntl(the##name->fd, F_SETFD, ffd & ~FD_CLOEXEC); \
+ /* if (ffd < 0) \
+ * XXX: What to do in this case? No good ideas. \
+ */ \
+ the##name->flag |= APR_INHERIT; \
+ apr_pool_child_cleanup_set(the##name->pool, \
+ (void *)the##name, \
+ cleanup, apr_pool_cleanup_null); \
+ } \
+ return APR_SUCCESS; \
+}
+
+#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, fd, pool, cleanup) \
+apr_status_t apr_##name##_inherit_unset(apr_##name##_t *the##name) \
+{ \
+ if (the##name->flag & APR_INHERIT) { \
+ int ffd = fcntl(the##name->fd, F_GETFD, 0); \
+ if (ffd >= 0) \
+ ffd = fcntl(the##name->fd, F_SETFD, ffd | FD_CLOEXEC); \
+ /* if (ffd < 0) \
+ * XXX: What to do in this case? No good ideas. \
+ */ \
+ the##name->flag &= ~APR_INHERIT; \
+ apr_pool_child_cleanup_set(the##name->pool, \
+ (void *)the##name, \
+ cleanup, cleanup); \
+ } \
+ return APR_SUCCESS; \
+}
+
+#else
+
+#define APR_IMPLEMENT_INHERIT_SET(name, flag, fd, pool, cleanup) \
apr_status_t apr_##name##_inherit_set(apr_##name##_t *the##name) \
{ \
if (!(the##name->flag & APR_INHERIT)) { \
@@ -69,14 +109,9 @@
cleanup, apr_pool_cleanup_null); \
} \
return APR_SUCCESS; \
-} \
-/* Deprecated */ \
-void apr_##name##_set_inherit(apr_##name##_t *the##name) \
-{ \
- apr_##name##_inherit_set(the##name); \
}
-#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, pool, cleanup) \
+#define APR_IMPLEMENT_INHERIT_UNSET(name, flag, fd, pool, cleanup) \
apr_status_t apr_##name##_inherit_unset(apr_##name##_t *the##name) \
{ \
if (the##name->flag & APR_INHERIT) { \
@@ -86,7 +121,16 @@
cleanup, cleanup); \
} \
return APR_SUCCESS; \
-} \
+}
+
+#endif
+
+/* Deprecated */ \
+void apr_##name##_set_inherit(apr_##name##_t *the##name) \
+{ \
+ apr_##name##_inherit_set(the##name); \
+}
+
/* Deprecated */ \
void apr_##name##_unset_inherit(apr_##name##_t *the##name) \
{ \
Index: network_io/unix/sockets.c
===================================================================
RCS file: /home/cvs/apr/network_io/unix/sockets.c,v
retrieving revision 1.107
diff -u -r1.107 sockets.c
--- network_io/unix/sockets.c 6 Jan 2003 23:44:35 -0000 1.107
+++ network_io/unix/sockets.c 18 Mar 2003 05:38:41 -0000
@@ -391,9 +391,9 @@
return APR_SUCCESS;
}
-APR_IMPLEMENT_INHERIT_SET(socket, inherit, cntxt, socket_cleanup)
+APR_IMPLEMENT_INHERIT_SET(socket, inherit, socketdes, cntxt, socket_cleanup)
-APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, cntxt, socket_cleanup)
+APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, socketdes, cntxt, socket_cleanup)
/* deprecated */
apr_status_t apr_shutdown(apr_socket_t *thesocket, apr_shutdown_how_e how)