/*
* 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"
#include "lint.h"
#include "thr_uberdata.h"
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <thread.h>
#include <pthread.h>
#include <synch.h>
#include <port.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include "sigev_thread.h"
/*
* There is but one spawner for all aio operations.
*/
/*
* Set non-zero via _RT_DEBUG to enable debugging printf's.
*/
static int _rt_debug = 0;
void
init_sigev_thread(void)
{
char *ldebug;
}
/*
* Routine to print debug messages:
* If _rt_debug is set, printf the debug message to stderr
* with an appropriate prefix.
*/
/*PRINTFLIKE1*/
static void
{
if (_rt_debug) {
}
}
/*
* The notify_thread() function can be used as the start function of a new
* thread but it is normally called from notifier(), below, in the context
* of a thread pool worker thread. It is used as the start function of a
* new thread only when individual pthread attributes differ from those
* that are common to all workers. This only occurs in the AIO case.
*/
static void *
{
return (NULL);
}
/*
* Thread pool interface to call the user-supplied notification function.
*/
static void
{
(void) notify_thread(arg);
}
/*
* This routine adds a new work request, described by function
* and argument, to the list of outstanding jobs.
* It returns 0 indicating success. A value != 0 indicates an error.
*/
static int
{
return (EINVAL);
return (errno);
return (errno);
}
return (0);
}
static void
{
/*
* synchronize with del_sigev_mq()
*/
tcdp->tcd_server_id = 0;
if (tcdp->tcd_msg_closing) {
return; /* del_sigev_mq() will free the tcd */
}
}
/*
* now delete everything
*/
}
/*
* timer_spawner(), mqueue_spawner(), and aio_spawner() are the main
* functions for the daemon threads that get the event(s) for the
* respective SIGEV_THREAD subsystems. There is one timer spawner for
* each timer_create(), one mqueue spawner for every mq_open(), and
* exactly one aio spawner for all aio requests. These spawners add
* work requests to be done by a pool of daemon worker threads. In case
* the event requires creation of a worker thread with different pthread
* attributes than those from the pool of workers, a new daemon thread
* with these attributes is spawned apart from the pool of workers.
* If the spawner fails to add work or fails to create an additional
* thread because of lacking resources, it puts the event back into
* the kernel queue and re-tries some time later.
*/
void *
{
/* destroy the pool if we are cancelled */
for (;;) {
dprintf("port_get on port %d failed with %d <%s>\n",
break;
}
switch (port_event.portev_source) {
case PORT_SOURCE_TIMER:
break;
case PORT_SOURCE_ALERT:
goto out;
default:
dprintf("port_get on port %d returned %u "
"(not PORT_SOURCE_TIMER)\n",
goto out;
}
if (sigev_add_work(tcdp,
break;
/* wait until job is done before looking for another */
}
out:
return (NULL);
}
void *
{
int ret = 0;
int ntype;
/* destroy the pool if we are cancelled */
while (ret == 0) {
continue;
tcdp->tcd_msg_enabled = 0;
/* ASSERT(ntype == SIGEV_THREAD || ntype == SIGEV_PORT); */
if (ntype == SIGEV_THREAD) {
} else { /* ntype == SIGEV_PORT */
}
}
return (NULL);
}
void *
{
int error = 0;
/* destroy the pool if we are cancelled */
while (error == 0) {
dprintf("port_get on port %d failed with %d <%s>\n",
break;
}
switch (port_event.portev_source) {
case PORT_SOURCE_AIO:
break;
case PORT_SOURCE_ALERT:
goto out;
default:
dprintf("port_get on port %d returned %u "
"(not PORT_SOURCE_AIO)\n",
goto out;
}
switch (port_event.portev_events) {
case AIOLIO:
#if !defined(_LP64)
case AIOLIO64:
#endif
break;
case AIOAREAD:
case AIOAWRITE:
case AIOFSYNC:
{
break;
}
#if !defined(_LP64)
case AIOAREAD64:
case AIOAWRITE64:
case AIOFSYNC64:
{
break;
}
#endif
default:
break;
}
else {
/*
* The attributes don't match.
* Spawn a thread with the non-matching attributes.
*/
else
if (error == 0) {
(void) pthread_attr_setdetachstate(
(void) pthread_attr_setdaemonstate_np(
(void) pthread_attr_destroy(&local_attr);
}
}
if (error) {
dprintf("Cannot add work, error=%d <%s>.\n",
/* (Temporary) no resources are available. */
port_event.portev_user) != 0)
break;
error = 0;
}
}
}
out:
return (NULL);
}
/*
* Allocate a thread_communication_data_t block.
*/
static thread_communication_data_t *
{
}
return (tcdp);
}
/*
* Free a thread_communication_data_t block.
*/
void
{
}
switch (tcdp->tcd_subsystem) {
case TIMER:
case AIO:
break;
case MQ:
tcdp->tcd_msg_enabled = 0;
break;
}
}
/*
* Initialize data structure and create the port.
*/
{
int error;
return (NULL);
}
return (NULL);
}
else {
/*
* We cannot just copy the sigevp->sigev_notify_attributes
* pointer. We need to initialize a new pthread_attr_t
* structure with the values from the user-supplied
* pthread_attr_t.
*/
if (error) {
return (NULL);
}
}
return (NULL);
}
}
return (tcdp);
}
/*
* Create a thread pool and launch the spawner.
*/
int
{
int ret;
int maxworkers;
void *(*spawner)(void *);
switch (tcdp->tcd_subsystem) {
case TIMER:
maxworkers = 1;
break;
case MQ:
maxworkers = 1;
break;
case AIO:
maxworkers = 100;
break;
default:
return (-1);
}
return (-1);
/* create the spawner with all signals blocked */
(void) sigfillset(&set);
if (ret != 0) {
return (-1);
}
return (0);
}
/*
* Delete the data associated with the sigev_thread timer, if timer is
* associated with such a notification option.
* Destroy the timer_spawner thread.
*/
int
{
int rc = 0;
}
}
}
return (rc);
}
int
{
return (tcdp->tcd_overruns);
return (0);
}
static void
{
}
/*
* Delete the data associated with the sigev_thread message queue,
* if the message queue is associated with such a notification option.
* Destroy the mqueue_spawner thread.
*/
void
{
int rc;
dprintf("Fail to cancel %u with error %d <%s>.\n",
return;
}
/*
* wait for sigev_destroy_pool() to finish
*/
}
/*
* POSIX aio:
* If the notification type is SIGEV_THREAD, set up
* the port number for notifications. Create the
* thread pool and launch the spawner if necessary.
* If the notification type is not SIGEV_THREAD, do nothing.
*/
int
{
static int sigev_aio_busy = 0;
int port;
int cancel_state;
int rc = 0;
return (0);
while (sigev_aio_busy)
else {
sigev_aio_busy = 1;
port = -1;
rc = -1;
} else if (launch_spawner(tcdp) != 0) {
port = -1;
rc = -1;
} else {
}
sigev_aio_busy = 0;
(void) cond_broadcast(&sigev_aio_cv);
}
return (rc);
}
int
{
return (0);
}
#if !defined(_LP64)
int
{
return (0);
}
#endif
/*
* Cleanup POSIX aio after fork1() in the child process.
*/
void
{
}
}
/*
* Utility function for the various postfork1_child_sigev_*() functions.
* Clean up the tcdp data structure and close the port.
*/
void
{
tcdp->tcd_server_id = 0;
}