You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by bn...@apache.org on 2001/08/02 22:29:14 UTC

cvs commit: apr/threadproc/NetWare threadpriv.c thread.c signals.c procsup.c proc.c

bnicholes    01/08/02 13:29:14

  Added:       threadproc/NetWare threadpriv.c thread.c signals.c procsup.c
                        proc.c
  Log:
  NetWare port of the threadproc functions
  
  Revision  Changes    Path
  1.1                  apr/threadproc/NetWare/threadpriv.c
  
  Index: threadpriv.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include "apr_portable.h"
  #include "threadproc.h"
  
  apr_status_t apr_threadkey_private_create(apr_threadkey_t **key, 
                                          void (*dest)(void *), apr_pool_t *cont) 
  {
      apr_status_t stat;
      
      (*key) = (apr_threadkey_t *)apr_palloc(cont, sizeof(apr_threadkey_t));
  	if ((*key) == NULL) {
          return APR_ENOMEM;
      }
  
      (*key)->cntxt = cont;
  
      if ((stat = NXKeyCreate(NULL, dest, &(*key)->key)) == 0) {
          return stat;
      }
      return stat;
  }
  
  apr_status_t apr_threadkey_private_get(void **new, apr_threadkey_t *key)
  {
      apr_status_t stat;
      
      if ((stat = NXKeyGetValue(key->key, new)) == 0) {
          return APR_SUCCESS;
      }
      else {
          return stat;    
      }
  }
  
  apr_status_t apr_threadkey_private_set(void *priv, apr_threadkey_t *key)
  {
      apr_status_t stat;
      if ((stat = NXKeySetValue(key->key, priv)) == 0) {
          return APR_SUCCESS;
      }
      else {
          return stat;
      }
  }
  
  apr_status_t apr_threadkey_private_delete(apr_threadkey_t *key)
  {
      apr_status_t stat;
      if ((stat = NXKeyDelete(key->key)) == 0) {
          return APR_SUCCESS; 
      }
      return stat;
  }
  
  apr_status_t apr_threadkey_data_get(void **data, const char *key, apr_threadkey_t *threadkey)
  {
      return apr_pool_userdata_get(data, key, threadkey->cntxt);
  }
  
  apr_status_t apr_threadkey_data_set(void *data,
                                   const char *key, apr_status_t (*cleanup) (void *),
                                   apr_threadkey_t *threadkey)
  {
      return apr_pool_userdata_set(data, key, cleanup, threadkey->cntxt);
  }
  
  apr_status_t apr_os_threadkey_get(apr_os_threadkey_t *thekey,
                                                 apr_threadkey_t *key)
  {
      thekey = &(key->key);
      return APR_SUCCESS;
  }
  
  apr_status_t apr_os_threadkey_put(apr_threadkey_t **key, 
                                  apr_os_threadkey_t *thekey, apr_pool_t *cont)
  {
      if (cont == NULL) {
          return APR_ENOPOOL;
      }
      if ((*key) == NULL) {
          (*key) = (apr_threadkey_t *)apr_palloc(cont, sizeof(apr_threadkey_t));
          (*key)->cntxt = cont;
      }
      (*key)->key = *thekey;
      return APR_SUCCESS;
  }           
  
  
  
  
  1.1                  apr/threadproc/NetWare/thread.c
  
  Index: thread.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include "apr.h"
  #include "apr_portable.h"
  #include "threadproc.h"
  
  
  apr_status_t apr_threadattr_create(apr_threadattr_t **new,
                                                  apr_pool_t *cont)
  {
      (*new) = (apr_threadattr_t *)apr_palloc(cont, 
                sizeof(apr_threadattr_t));
  
      if ((*new) == NULL) {
          return APR_ENOMEM;
      }
  
      (*new)->cntxt = cont;
      return APR_SUCCESS;
  }
  
  apr_status_t apr_threadattr_detach_set(apr_threadattr_t *attr,apr_int32_t on)
  {
      attr->detach = on;
  	return APR_SUCCESS;   
  }
  
  apr_status_t apr_threadattr_detach_get(apr_threadattr_t *attr)
  {
      if (attr->detach == 1)
          return APR_DETACH;
      return APR_NOTDETACH;
  }
  
  apr_status_t apr_thread_create(apr_thread_t **new,
   											apr_threadattr_t *attr, 
                               				apr_thread_start_t func,
   											void *data,
   											apr_pool_t *cont)
  {
      apr_status_t stat;
      size_t stacksize;
      long flags = NX_CTX_AUTO_CLEANUP;
    	char threadName[NX_MAX_OBJECT_NAME_LEN+1];
     	//srj added for nks giving the threads names
  	
  	sprintf(threadName, "Apache-2.0 %003ld",data);
      
      (*new) = (apr_thread_t *)apr_palloc(cont, sizeof(apr_thread_t));
  
      if ((*new) == NULL) {
          return APR_ENOMEM;
      }
      
      (*new)->cntxt = cont;
      
      stat = apr_pool_create(&(*new)->cntxt, cont);
      if (stat != APR_SUCCESS) {
          return stat;
      }
      
      if (attr) {
          stacksize = attr->stack_size; 
          if (attr->detach)
              flags |= NX_THR_DETACHED;
          else
              flags |= NX_THR_JOINABLE;
      }
      else {
          stacksize = APR_DEFAULT_STACK_SIZE;
          flags |= NX_THR_JOINABLE;
      }
      
      (*new)->ctx = NXContextAlloc(
      	/* void(*start_routine)(void *arg)*/(void (*)(void *)) func,
       	/* void *arg */										   data,
       	/* int priority */ 									   NX_PRIO_MED,
       	/* NXSize_t stackSize */							   stacksize,
       	/* long flags */									   NX_CTX_NORMAL,
       	/* int *error */									   &stat);
  		
       	                                                                   
    	stat = NXContextSetName(
  		 	/* NXContext_t ctx */			(*new)->ctx,
  			/* const char *name */			threadName);
  
    	stat = NXThreadCreate(
          	/* NXContext_t context */		(*new)->ctx,
          	/* long flags */				flags,
          	/* NXThreadId_t *thread_id */	&(*new)->td);
  
      if(stat==0)
       	return APR_SUCCESS;
          
  	return(stat);// if error    
  }
  
  apr_os_thread_t apr_os_thread_current()
  {
      return NXThreadGetId();
  }
  
  int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2)
  {
      return (tid1 == tid2);
  }
  
  apr_status_t apr_thread_yield()
  {
      NXThreadYield();
      return APR_SUCCESS;
  }
  
  apr_status_t apr_thread_exit(apr_thread_t *thd,
                                            apr_status_t *retval)
  {
      apr_pool_destroy(thd->cntxt);
      NXThreadExit((void *)*retval);
      return APR_SUCCESS;
  }
  
  apr_status_t apr_thread_join(apr_status_t *retval,
                                            apr_thread_t *thd)
  {
      apr_status_t  stat;    
      NXThreadId_t dthr;
  
      if ((stat = NXThreadJoin(thd->td, &dthr, (void *)&retval)) == 0) {
          return APR_SUCCESS;
      }
      else {
          return stat;
      }
  }
  
  apr_status_t apr_thread_detach(apr_thread_t *thd)
  {
      return APR_SUCCESS;
  }
  
  apr_status_t apr_thread_data_get(void **data, const char *key,
                                               apr_thread_t *thread)
  {
      if (thread != NULL) {
              return apr_pool_userdata_get(data, key, thread->cntxt);
      }
      else {
          data = NULL;
          return APR_ENOTHREAD;
      }
  }
  
  apr_status_t apr_thread_data_set(void *data, const char *key,
                                apr_status_t (*cleanup) (void *),
                                apr_thread_t *thread)
  {
      if (thread != NULL) {
         return apr_pool_userdata_set(data, key, cleanup, thread->cntxt);
      }
      else {
          data = NULL;
          return APR_ENOTHREAD;
      }
  }
  
  
  /*SRJ Need to resolve
   APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd,
                                              apr_thread_t *thd)
  {
      if (thd == NULL) {
          return APR_ENOTHREAD;
      }
      *thethd = thd->td;
      return APR_SUCCESS;
  }
  
  APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd,
                                              apr_os_thread_t *thethd,
                                              apr_pool_t *cont)
  {
      if (cont == NULL) {
          return APR_ENOPOOL;
      }
      if ((*thd) == NULL) {
          (*thd) = (apr_thread_t *)apr_palloc(cont, sizeof(apr_thread_t));
          (*thd)->cntxt = cont;
      }
      (*thd)->td = thethd;
      return APR_SUCCESS;
  }
  
  */
  
  
  1.1                  apr/threadproc/NetWare/signals.c
  
  Index: signals.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include "threadproc.h"
  #include <nks/thread.h>
  #include "apr_private.h"
  #include "apr_pools.h"
  #include "apr_signal.h"
  #include "apr_strings.h"
  
  #define APR_WANT_SIGNAL
  #include "apr_want.h"
  
  #include <assert.h>
  #if APR_HAS_THREADS && APR_HAVE_PTHREAD_H
  #include <pthread.h>
  #endif
  
  apr_status_t apr_proc_kill(apr_proc_t *proc, int signum)
  {
  #ifndef NETWARE
      if (kill(proc->pid, signum) == -1) {
          return errno;
      }
  #endif
  
      //srj need to find equal to kill or use sigterm in nks
  	//srj windows is using TerminateProcess here
      //srj if ( NXThreadExit(proc->pid) != 0) {
      //srj    return errno;
      //srj }
      return APR_SUCCESS;
  }
  
  
  void apr_signal_init(apr_pool_t *pglobal)
  {
  }
  
  const char *apr_signal_get_description(int signum)
  {
      return "unknown signal (not supported)";
  }
  
  static void *signal_thread_func(void *signal_handler)
  {
      return NULL;
  }
  
  apr_status_t apr_setup_signal_thread(void)
  {
      int rv = 0;
  
      return rv;
  }
  
  
  
  
  1.1                  apr/threadproc/NetWare/procsup.c
  
  Index: procsup.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include "threadproc.h"
  
  apr_status_t apr_proc_detach(void)
  {
  #if 0
      int x;
      pid_t pgrp;
  
      chdir("/");
  #if !defined(MPE) && !defined(OS2) && !defined(TPF) && !defined(BEOS)
  /* Don't detach for MPE because child processes can't survive the death of
     the parent. */
      if ((x = fork()) > 0)
          exit(0);
      else if (x == -1) {
          perror("fork");
          fprintf(stderr, "unable to fork new process\n");
          exit(1);  /* we can't do anything here, so just exit. */
      }
  /*    RAISE_SIGSTOP(DETACH);*/
  #endif
  #if APR_HAVE_SETSID
      if ((pgrp = setsid()) == -1) {
          return errno;
      }
  #elif defined(NEXT) || defined(NEWSOS)
      if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
          return errno;
      }
  #elif defined(OS2) || defined(TPF)
      /* OS/2 don't support process group IDs */
      pgrp = getpid();
  #elif defined(MPE)
      /* MPE uses negative pid for process group */
      pgrp = -getpid();
  #else
      if ((pgrp = setpgid(0, 0)) == -1) {
          return errno;
      }
  #endif
  
      /* close out the standard file descriptors */
      if (freopen("/dev/null", "r", stdin) == NULL) {
          return errno;
          /* continue anyhow -- note we can't close out descriptor 0 because we
           * have nothing to replace it with, and if we didn't have a descriptor
           * 0 the next file would be created with that value ... leading to
           * havoc.
           */
      }
      if (freopen("/dev/null", "w", stdout) == NULL) {
          return errno;
      }
       /* We are going to reopen this again in a little while to the error
        * log file, but better to do it twice and suffer a small performance
        * hit for consistancy than not reopen it here.
        */
      if (freopen("/dev/null", "w", stderr) == NULL) {
          return errno;
      }
  #endif
      return APR_SUCCESS;
  }
  
  #if 0
  #if (!HAVE_WAITPID)
  /* From ikluft@amdahl.com
   * this is not ideal but it works for SVR3 variants
   * Modified by dwd@bell-labs.com to call wait3 instead of wait because
   *   apache started to use the WNOHANG option.
   */
  int waitpid(pid_t pid, int *statusp, int options)
  {
      int tmp_pid;
      if (kill(pid, 0) == -1) {
          errno = ECHILD;
          return -1;
      }
      while (((tmp_pid = wait3(statusp, options, 0)) != pid) &&
                  (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
          ;
      return tmp_pid;
  }
  #endif
  #endif
  
  
  
  
  1.1                  apr/threadproc/NetWare/proc.c
  
  Index: proc.c
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  #include "threadproc.h"
  #include "fileio.h"
  #include "apr_strings.h"
  #include "apr_portable.h"
  
  /* 
   * some of the ideas expressed herein are based off of Microsoft
   * Knowledge Base article: Q190351
   *
   */
  apr_status_t apr_procattr_create(apr_procattr_t **new,apr_pool_t *cont)
  {
      (*new) = (apr_procattr_t *)apr_pcalloc(cont, sizeof(apr_procattr_t));
  
      if ((*new) == NULL) {
          return APR_ENOMEM;
      }
      (*new)->cntxt = cont;
      (*new)->cmdtype = APR_PROGRAM;
      return APR_SUCCESS;
  
  }
  
  apr_status_t apr_procattr_io_set(apr_procattr_t *attr, apr_int32_t in, 
                                   apr_int32_t out, apr_int32_t err)
  {
      apr_status_t status;
      if (in != 0) {
          if ((status = apr_file_pipe_create(&attr->child_in, &attr->parent_in, 
                                     attr->cntxt)) != APR_SUCCESS) {
              return status;
          }
          switch (in) {
          case APR_FULL_BLOCK:
              break;
          case APR_PARENT_BLOCK:
              apr_file_pipe_timeout_set(attr->child_in, 0);
              break;
          case APR_CHILD_BLOCK:
              apr_file_pipe_timeout_set(attr->parent_in, 0);
              break;
          default:
              apr_file_pipe_timeout_set(attr->child_in, 0);
              apr_file_pipe_timeout_set(attr->parent_in, 0);
          }
      } 
      if (out) {
          if ((status = apr_file_pipe_create(&attr->parent_out, &attr->child_out, 
                                     attr->cntxt)) != APR_SUCCESS) {
              return status;
          }
          switch (out) {
          case APR_FULL_BLOCK:
              break;
          case APR_PARENT_BLOCK:
              apr_file_pipe_timeout_set(attr->child_out, 0);
              break;
          case APR_CHILD_BLOCK:
              apr_file_pipe_timeout_set(attr->parent_out, 0);
              break;
          default:
              apr_file_pipe_timeout_set(attr->child_out, 0);
              apr_file_pipe_timeout_set(attr->parent_out, 0);
          }
      } 
      if (err) {
          if ((status = apr_file_pipe_create(&attr->parent_err, &attr->child_err, 
                                     attr->cntxt)) != APR_SUCCESS) {
              return status;
          }
          switch (err) {
          case APR_FULL_BLOCK:
              break;
          case APR_PARENT_BLOCK:
              apr_file_pipe_timeout_set(attr->child_err, 0);
              break;
          case APR_CHILD_BLOCK:
              apr_file_pipe_timeout_set(attr->parent_err, 0);
              break;
          default:
              apr_file_pipe_timeout_set(attr->child_err, 0);
              apr_file_pipe_timeout_set(attr->parent_err, 0);
          }
      } 
      return APR_SUCCESS;
  }
  
  
  apr_status_t apr_procattr_child_in_set(apr_procattr_t *attr, apr_file_t *child_in,
                                     apr_file_t *parent_in)
  {
      if (attr->child_in == NULL && attr->parent_in == NULL)
          apr_file_pipe_create(&attr->child_in, &attr->parent_in, attr->cntxt);
  
      if (child_in != NULL)
          apr_file_dup(&attr->child_in, child_in, attr->cntxt);
  
      if (parent_in != NULL)
          apr_file_dup(&attr->parent_in, parent_in, attr->cntxt);
  
      return APR_SUCCESS;
  }
  
  
  apr_status_t apr_procattr_child_out_set(apr_procattr_t *attr, apr_file_t *child_out,
                                      apr_file_t *parent_out)
  {
      if (attr->child_out == NULL && attr->parent_out == NULL)
          apr_file_pipe_create(&attr->child_out, &attr->parent_out, attr->cntxt);
  
      if (child_out != NULL)
          apr_file_dup(&attr->child_out, child_out, attr->cntxt);
  
      if (parent_out != NULL)
          apr_file_dup(&attr->parent_out, parent_out, attr->cntxt);
  
      return APR_SUCCESS;
  }
  
  
  apr_status_t apr_procattr_child_err_set(apr_procattr_t *attr, apr_file_t *child_err,
                                     apr_file_t *parent_err)
  {
      if (attr->child_err == NULL && attr->parent_err == NULL)
          apr_file_pipe_create(&attr->child_err, &attr->parent_err, attr->cntxt);
  
      if (child_err != NULL)
          apr_file_dup(&attr->child_err, child_err, attr->cntxt);
  
      if (parent_err != NULL)
          apr_file_dup(&attr->parent_err, parent_err, attr->cntxt);
  
      return APR_SUCCESS;
  }
  
  
  apr_status_t apr_procattr_dir_set(apr_procattr_t *attr, 
                                 const char *dir) 
  {
      attr->currdir = apr_pstrdup(attr->cntxt, dir);
      if (attr->currdir) {
          return APR_SUCCESS;
      }
      return APR_ENOMEM;
  }
  
  apr_status_t apr_procattr_cmdtype_set(apr_procattr_t *attr,
                                       apr_cmdtype_e cmd) 
  {
      attr->cmdtype = cmd;
      return APR_SUCCESS;
  }
  
  apr_status_t apr_procattr_detach_set(apr_procattr_t *attr, apr_int32_t detach) 
  {
      attr->detached = detach;
      return APR_SUCCESS;
  }
  
  apr_status_t apr_proc_fork(apr_proc_t *proc, apr_pool_t *cont)
  {
  #if 0
      int pid;
      
      if ((pid = fork()) < 0) {
          return errno;
      }
      else if (pid == 0) {
          proc->pid = pid;
          proc->in = NULL; 
          proc->out = NULL; 
          proc->err = NULL; 
          return APR_INCHILD;
      }
      proc->pid = pid;
      proc->in = NULL; 
      proc->out = NULL; 
      proc->err = NULL; 
  #endif
      return APR_INPARENT;
  }
  
  static apr_status_t limit_proc(apr_procattr_t *attr)
  {
  #if APR_HAVE_STRUCT_RLIMIT && APR_HAVE_SETRLIMIT
  #ifdef RLIMIT_CPU
      if (attr->limit_cpu != NULL) {
          if ((setrlimit(RLIMIT_CPU, attr->limit_cpu)) != 0) {
              return errno;
          }
      }
  #endif
  #ifdef RLIMIT_NPROC
      if (attr->limit_nproc != NULL) {
          if ((setrlimit(RLIMIT_NPROC, attr->limit_nproc)) != 0) {
              return errno;
          }
      }
  #endif
  #if defined(RLIMIT_AS)
      if (attr->limit_mem != NULL) {
          if ((setrlimit(RLIMIT_AS, attr->limit_mem)) != 0) {
              return errno;
          }
      }
  #elif defined(RLIMIT_DATA)
      if (attr->limit_mem != NULL) {
          if ((setrlimit(RLIMIT_DATA, attr->limit_mem)) != 0) {
              return errno;
          }
      }
  #elif defined(RLIMIT_VMEM)
      if (attr->limit_mem != NULL) {
          if ((setrlimit(RLIMIT_VMEM, attr->limit_mem)) != 0) {
              return errno;
          }
      }
  #endif
  #else
      /*
       * Maybe make a note in error_log that setrlimit isn't supported??
       */
  
  #endif
      return APR_SUCCESS;
  }
  
  apr_status_t apr_proc_create(apr_proc_t *new,
  									const char *progname, 
  									const char * const *args, 
  									const char * const *env,
                                		apr_procattr_t *attr, 
                                		apr_pool_t *cont)
  {
  #if 0
      int i;
      const char **newargs;
  
      new->in = attr->parent_in;
      new->err = attr->parent_err;
      new->out = attr->parent_out;
      if ((new->pid = fork()) < 0) {
          return errno;
      }
      else if (new->pid == 0) { 
          int status;
          /* child process */
          if (attr->child_in) {
              apr_file_close(attr->parent_in);
              dup2(attr->child_in->filedes, STDIN_FILENO);
              apr_file_close(attr->child_in);
          }
          if (attr->child_out) {
              apr_file_close(attr->parent_out);
              dup2(attr->child_out->filedes, STDOUT_FILENO);
              apr_file_close(attr->child_out);
          }
          if (attr->child_err) {
              apr_file_close(attr->parent_err);
              dup2(attr->child_err->filedes, STDERR_FILENO);
              apr_file_close(attr->child_err);
          }
          
          apr_signal(SIGCHLD, SIG_DFL); /*not sure if this is needed or not */
  
          if (attr->currdir != NULL) {
              if (chdir(attr->currdir) == -1) {
                  exit(-1);   /* We have big problems, the child should exit. */
              }
          }
  
          apr_pool_cleanup_for_exec();
  
          if ((status = limit_proc(attr)) != APR_SUCCESS) {
              return status;
          }
  
          if (attr->cmdtype == APR_SHELLCMD) {
              i = 0;
              while (args[i]) {
                  i++;
              }
              newargs =
                 (const char **) apr_palloc(cont, sizeof (char *) * (i + 3));
              newargs[0] = SHELL_PATH;
              newargs[1] = "-c";
              i = 0;
              while (args[i]) {
                  newargs[i + 2] = args[i]; 
                  i++;
              }
              newargs[i + 2] = NULL;
              if (attr->detached) {
                  apr_proc_detach();
              }
              execve(SHELL_PATH, (char * const *) newargs, (char * const *)env);
          }
          else {
              if (attr->detached) {
                  apr_proc_detach();
              }
              execve(progname, (char * const *)args, (char * const *)env);
          }
          exit(-1);  /* if we get here, there is a problem, so exit with an */ 
                     /* error code. */
      }
      /* Parent process */
      if (attr->child_in) {
          apr_file_close(attr->child_in);
      }
      if (attr->child_out) {
          apr_file_close(attr->child_out);
      }
      if (attr->child_err) {
          apr_file_close(attr->child_err);
      }
  #endif
      return APR_SUCCESS;
  }
  
  apr_status_t apr_proc_wait_all_procs(apr_proc_t *proc, apr_wait_t *status,
                                apr_wait_how_e waithow, apr_pool_t *p)
  {
  #if 0
      int waitpid_options = WUNTRACED;
  
      if (waithow != APR_WAIT) {
          waitpid_options |= WNOHANG;
      }
  
      if ((proc->pid = waitpid(-1, status, waitpid_options)) > 0) {
          return APR_CHILD_DONE;
      }
      else if (proc->pid == 0) {
          return APR_CHILD_NOTDONE;
      }
  #endif
      return errno;
  } 
  
  apr_status_t apr_proc_wait(apr_proc_t *proc, 
                             apr_wait_how_e waithow)
  {
  #if 0
      pid_t status;
  
      if (waithow == APR_WAIT) {
          if ((status = waitpid(proc->pid, NULL, WUNTRACED)) > 0) {
              return APR_CHILD_DONE;
          }
          else if (status == 0) {
              return APR_CHILD_NOTDONE;
          }
          return errno;
      }
      if ((status = waitpid(proc->pid, NULL, WUNTRACED | WNOHANG)) > 0) {
          return APR_CHILD_DONE;
      }
      else if (status == 0) {
          return APR_CHILD_NOTDONE;
      }
  #endif
      return errno;
  } 
  
  apr_status_t apr_procattr_limit_set(apr_procattr_t *attr, apr_int32_t what, 
                            struct rlimit *limit)
  {
      switch(what) {
          case APR_LIMIT_CPU:
  #ifdef RLIMIT_CPU
              attr->limit_cpu = limit;
              break;
  #else
              return APR_ENOTIMPL;
  #endif
          case APR_LIMIT_MEM:
  #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)
              attr->limit_mem = limit;
              break;
  #else
              return APR_ENOTIMPL;
  #endif
          case APR_LIMIT_NPROC:
  #ifdef RLIMIT_NPROC
              attr->limit_nproc = limit;
              break;
  #else
              return APR_ENOTIMPL;
  #endif
      }
      return APR_SUCCESS;
  }