wait.c revision 63c7f71bccc7117f1823a1fc784ada39d0cade44
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* wait.c - asynchronous monitoring of "wait registered" start methods
*
* Use event ports to poll on the set of fds representing the /proc/[pid]/psinfo
* files. If one of these fds returns an event, then we inform the restarter
* that it has stopped.
*
* The wait_info_list holds the series of processes currently being monitored
* for exit. The wi_fd member, which contains the file descriptor of the psinfo
* file being polled upon ("event ported upon"), will be set to -1 if the file
* descriptor is inactive (already closed or not yet opened).
*/
#ifdef _FILE_OFFSET_BITS
#endif /* _FILE_OFFSET_BITS */
#include <sys/resource.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <libuutil.h>
#include <poll.h>
#include <port.h>
#include <pthread.h>
#include <procfs.h>
#include <string.h>
#include <stropts.h>
#include <unistd.h>
#include "startd.h"
static int port_fd;
static scf_handle_t *wait_hndl;
static struct rlimit init_fd_rlimit;
static uu_list_pool_t *wait_info_pool;
static uu_list_t *wait_info_list;
static pthread_mutex_t wait_info_lock;
/*
* void wait_remove(wait_info_t *, int)
* Remove the given wait_info structure from our list, performing various
* cleanup operations along the way. If the direct flag is false (meaning
* that we are being called with from restarter instance list context) and
* the instance should not be ignored, then notify the restarter that the
* associated instance has exited. If the wi_ignore flag is true then it
* means that the stop was initiated from within svc.startd, rather than
* from outside it.
*
* Since we may no longer be the startd that started this process, we only are
* concerned with a waitpid(3C) failure if the wi_parent field is non-zero.
*/
static void
{
int status;
} else {
if (WEXITSTATUS(status) != 0) {
}
}
}
/*
* Make an attempt to clear out any utmpx record associated with this
* PID.
*/
/*
* Bind wait_hndl lazily.
*/
for (wait_hndl =
"bind a new repository handle: %s\n",
scf_strerror(scf_error()));
(void) sleep(2);
}
}
}
}
/*
* void wait_ignore_by_fmri(const char *)
* wait_ignore_by_fmri is called when svc.startd is going to stop the
* instance. Since we need to wait on the process and close the utmpx record,
* we're going to set the wi_ignore flag, so that when the process exits we
* clean up, but don't tell the restarter to stop it.
*/
void
wait_ignore_by_fmri(const char *fmri)
{
break;
}
}
}
/*
* int wait_register(pid_t, char *, int, int)
* wait_register is called after we have called fork(2), and know which pid we
* wish to monitor. However, since the child may have already exited by the
* time we are called, we must handle the error cases from open(2)
* appropriately. The am_parent flag is recorded to handle waitpid(2)
* behaviour on removal; similarly, the direct flag is passed through to a
* potential call to wait_remove() to govern its behaviour in different
* contexts.
*
* Returns 0 if registration successful, 1 if child pid did not exist, and -1
* if a different error occurred.
*/
int
{
int fd;
return (-1);
/*
* Child has already exited.
*/
return (1);
} else {
"open %s failed; not monitoring %s: %s\n", fname,
return (-1);
}
}
"initial port_association of %d / %s failed: %s\n", fd,
return (-1);
}
return (0);
}
/*ARGSUSED*/
void *
wait_thread(void *args)
{
for (;;) {
int fd;
continue;
else {
"port_get() failed with %s\n",
}
}
sizeof (psinfo_t)) {
"couldn't get psinfo data for %s (%s); "
goto err_remove;
}
/*
* We have determined, in accordance with the
* definition in proc(4), this process is not a
* zombie. Reassociate.
*/
0, wi))
"port_association of %d / %s "
continue;
}
} else if (
"port_association of %d / %s "
continue;
}
wait_remove(wi, 0);
}
/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
}
void
{
}
void
{
if (pid != 0)
return;
/*
* Close all of the child's wait-related fds. The wait_thread() is
* gone, so no need to worry about returning events. We always exec(2)
* after a fork request, so we needn't free the list elements
* themselves.
*/
}
}
void
{
uu_die("wait_init couldn't port_create");
if (wait_info_pool == NULL)
uu_die("wait_init couldn't create wait_info_pool");
if (wait_info_list == NULL)
uu_die("wait_init couldn't create wait_info_list");
}