aboutsummaryrefslogtreecommitdiff
path: root/threadproc/unix/proc.c
diff options
context:
space:
mode:
authorMladen Turk <mturk@apache.org>2009-02-21 20:59:46 +0000
committerMladen Turk <mturk@apache.org>2009-02-21 20:59:46 +0000
commit4f5598d1c67dd5e66f9bf5908ca10e2ed192ba9e (patch)
tree3b4ee5b6141ac3deeaf25152466a633db83836be /threadproc/unix/proc.c
parent46fbd0c7729b151f54a936e477b29e2de463a069 (diff)
downloadapr-4f5598d1c67dd5e66f9bf5908ca10e2ed192ba9e.tar.gz
apr-4f5598d1c67dd5e66f9bf5908ca10e2ed192ba9e.zip
Add simple parent/child data exchange for APR processes
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@746589 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'threadproc/unix/proc.c')
-rw-r--r--threadproc/unix/proc.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/threadproc/unix/proc.c b/threadproc/unix/proc.c
index 6c4786653..ed715e694 100644
--- a/threadproc/unix/proc.c
+++ b/threadproc/unix/proc.c
@@ -19,6 +19,7 @@
#include "apr_portable.h"
#include "apr_signal.h"
#include "apr_random.h"
+#include "apr_arch_proc_mutex.h"
/* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE
* requested for a specific child handle;
@@ -216,6 +217,69 @@ APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr,
return APR_SUCCESS;
}
+APR_DECLARE(apr_status_t) apr_procattr_ipc_data_set(apr_procattr_t *attr,
+ const void *data,
+ apr_size_t size)
+{
+ attr->ipc_data = data;
+ attr->ipc_size = size;
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_procattr_ipc_data_get(apr_procattr_t *attr,
+ void **data,
+ apr_size_t *size)
+{
+ if (attr->ipc_shm && attr->ipc_size) {
+ *data = apr_shm_baseaddr_get(attr->ipc_shm);
+ *size = attr->ipc_size;
+ return APR_SUCCESS;
+ }
+ else
+ return APR_EINIT;
+}
+
+/* Global ipc data setup if we are child
+ * of the process that used child_data_set
+ * TODO: This can probably be some struct.
+ */
+static void *ipc_shm_data = NULL;
+static apr_size_t ipc_shm_size = 0;
+static int ipc_shm_init = 0;
+
+apr_status_t apr_proc_ipc_init(apr_pool_t *pool)
+{
+ apr_status_t rv;
+ char shmname[64];
+ const char *tmpdir = NULL;
+ apr_shm_t *shm;
+
+ if (ipc_shm_init++)
+ return APR_SUCCESS;
+ apr_temp_dir_get(&tmpdir, pool);
+ apr_snprintf(shmname, sizeof(shmname), "%s/.apripc.%" APR_PID_T_FMT,
+ tmpdir, getpid());
+
+ if ((rv = apr_shm_attach(&shm, shmname, pool)) != APR_SUCCESS)
+ return rv;
+ ipc_shm_data = apr_shm_baseaddr_get(shm);
+ ipc_shm_size = apr_shm_size_get(shm);
+ return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_proc_parent_ipc_data_get(void **data,
+ apr_size_t *size)
+{
+ if (!ipc_shm_init)
+ return APR_EINIT;
+ if (!ipc_shm_data)
+ return APR_ENOMEM;
+
+ *data = ipc_shm_data;
+ *size = ipc_shm_size;
+ return APR_SUCCESS;
+}
+
APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool)
{
int pid;
@@ -353,7 +417,9 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
apr_pool_t *pool)
{
int i;
+ apr_status_t rc;
const char * const empty_envp[] = {NULL};
+ apr_proc_mutex_t *ipc_mutex = NULL;
if (!env) { /* Specs require an empty array instead of NULL;
* Purify will trigger a failure, even if many
@@ -392,6 +458,22 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
}
}
+ if (attr->ipc_data && attr->ipc_size) {
+ /* Create startup ipc mutex.
+ * The purpose of this mutex is to enable
+ * the 'start suspended' process behaviour.
+ * We need to create the shared memory after
+ * fork() and we don't know in advance what
+ * the child pid will be. Mutex locks the child
+ * until we create the shared memory which
+ * can be then attached at child's apr_initialize.
+ */
+ if ((rc = apr_proc_mutex_create(&ipc_mutex, NULL,
+ APR_LOCK_DEFAULT, attr->pool)) != APR_SUCCESS) {
+ return rc;
+ }
+ apr_proc_mutex_lock(ipc_mutex);
+ }
if ((new->pid = fork()) < 0) {
return errno;
}
@@ -399,6 +481,33 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
int status;
/* child process */
+ if (ipc_mutex) {
+ if ((rc = apr_proc_mutex_child_init(&ipc_mutex,
+ NULL, pool)) != APR_SUCCESS) {
+ /* This should never happen.
+ * We cannot continue.
+ */
+ if (attr->errfn) {
+ attr->errfn(pool, rc, "ipc mutex init failed");
+ }
+ _exit(-1);
+ }
+ /* Wait util the parent initializes shared memory.
+ */
+ if ((rc = apr_proc_mutex_lock(ipc_mutex)) != APR_SUCCESS) {
+ /* Locking failed.
+ * Probably the parent ended prematurely
+ */
+ if (attr->errfn) {
+ attr->errfn(pool, rc, "ipc mutex lock failed");
+ }
+ _exit(-1);
+ }
+ /* By now we should have the ipc shared memory set up.
+ * We don't need the mutex any more.
+ */
+ apr_proc_mutex_destroy(ipc_mutex);
+ }
/*
* If we do exec cleanup before the dup2() calls to set up pipes
* on 0-2, we accidentally close the pipes used by programs like
@@ -455,6 +564,7 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
apr_signal(SIGCHLD, SIG_DFL); /* not sure if this is needed or not */
+
if (attr->currdir != NULL) {
if (chdir(attr->currdir) == -1) {
if (attr->errfn) {
@@ -594,6 +704,35 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new,
_exit(-1); /* if we get here, there is a problem, so exit with an
* error code. */
}
+ if (ipc_mutex) {
+ char shmname[64];
+ const char *tmpdir = NULL;
+
+ apr_temp_dir_get(&tmpdir, pool);
+ apr_snprintf(shmname, sizeof(shmname), "%s/.apripc.%" APR_PID_T_FMT,
+ tmpdir, new->pid);
+ rc = apr_shm_create(&attr->ipc_shm, attr->ipc_size,
+ shmname, attr->pool);
+ if (rc == APR_SUCCESS) {
+ if (!geteuid()) {
+ /* Set ipc shared memory permissions for
+ * our child process.
+ */
+ APR_PERMS_SET_FN(shm)(attr->ipc_shm,
+ APR_FPROT_UREAD | APR_FPROT_UWRITE,
+ attr->uid, attr->gid);
+ }
+ /* Fill in shared memory with ipc data */
+ memcpy(apr_shm_baseaddr_get(attr->ipc_shm),
+ attr->ipc_data, attr->ipc_size);
+ }
+ /* Unlock the ipc startup mutex.
+ * This mutex is destroyed when attr->pool is cleared
+ * or destroyed because it might not yet be initialised
+ * inside the child.
+ */
+ apr_proc_mutex_unlock(ipc_mutex);
+ }
/* Parent process */
if (attr->child_in && (attr->child_in->filedes != -1)) {