/* TCP32DLL.LIB  SO32DLL.LIB for 16 bit stack */
/* compile with tcpip32.lib for 32 stack */
/*
 * $Id: main.c,v 1.28.6.15 2004/12/29 03:15:44 squidadm Exp $
 *
 * DEBUG: section 1     Startup and Main Loop
 * AUTHOR: Harvest Derived
 */

#include "squidDeclaration.h"

int CheckChangeDir(void);

#include "squid.h"

#ifdef _SQUID_OS2VAC_

 #define INCL_DOS
 #define INCL_DOSERRORS
 #include <os2.h>

 #include <direct.h>
 #include <float.h>
 #include <io.h>
 #include <sys\stat.h>
 #define chroot(name) 0

#include "OS2PipesCS.hpp"

#define STACK_SIZE      320000
#define MAX_NUM_THREADS 32

#define S_SHUTDOWN    0x101
#define S_RECONFIGURE 0x102
#define S_ROTATE      0x103
#define S_DEBUG       0x104
#define S_KILL        0x105
#define S_PRIORITY    0x106

/****** External functions ********/
/* for error reporting from xmalloc and friends */
extern void (*failure_notify) (const char *);
extern void setServerPriority(void);

int OS2SetRelMaxFH(int ReqCount);
char * GetOS2ErrorMessage(int ierr);


/****** Static variables ********/
static int opt_send_signal = -1;
static char opt_debug_str[20] ="";
static int opt_no_daemon = 0;
static int opt_parse_cfg_only = 0;
static int httpPortNumOverride = 1;
static int icpPortNumOverride = 1;     /* Want to detect "-u 0" */
static int configured_once = 0;
#if MALLOC_DBG
static int malloc_debug_level = 0;
#endif
static volatile int do_reconfigure = 0;
static volatile int do_rotate = 0;
static volatile int do_shutdown = 0;
int SquidServerMode = 0; /* =1 in sever mode i.e. main programm =0 in second calls like -k reconfigure */
static int SquidMainTID; /* T(hread)ID of the main squid thread; is used for dinamical priorities change */

/****** Internal functions ********/
static void mainRotate(void);
static void mainReconfigure(void);

//static void
SIGHDLR rotate_logs(int sig);

static SIGHDLR reconfigure(int sig);

static void mainInitialize(void);
static void usage(void);
static void mainParseOptions(int, char **);
static void sendSignal(void);
static void serverConnectionsOpen(void);
static void watch_child(char **);
#if MEM_GEN_TRACE
extern void log_trace_done();
extern void log_trace_init(char *);
#endif
static EVH SquidShutdown;
static int checkRunningPid(void);
int SendSignalToWorkindSquid(int opt_send_signal, char *senddata);

int startServerThreads(void);
void _Optlink SQUID_ClientWork(void *param);
void _Optlink SQUID_WatchDog(void *param);

int SquidKillAllChilds(void);
void _Optlink CloseAllFHatExit(void);

static const char *squid_start_script = "squid_start";
int index_fd_debug_log[8];



#if TEST_ACCESS
 //EK??#include "test_access.c"
#endif

char *DefaultConfigFileName(void)
{
    char *path, *buff;
    char name[] = "/etc/squid.conf";
    if((path = getenv("SQUID_DIRECTORY")) == 0) return NULL;
    buff = (char *) xmalloc(strlen(path) + sizeof(name));
    strcpy(buff, path);
    strcat(buff, name);
    return buff;
}


static void
usage(void)
{
    fprintf(stderr,
#if HAVE_SYSLOG
       "Usage: %s [-dhnsvzCDFHNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
#else
       "Usage: %s [-dhvzCDFHNRVYX] [-f config-file] [-[au] port] [-k signal]\n\t[-n num] [-д x,y] [-p uClass,delta]\n"
#endif
       "-a port  Specify HTTP port number (default: %d).\n"
       "-d level Write debugging to stderr also.\n"
       "-f file  Use given config-file instead of\n"
             "\t %s\n"
       "-h       Print help message.\n"
       "-k       reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
             "\t Parse configuration file, then send signal to \n"
             "\t running copy (except -k parse) and exit.\n"
       "-n sqNum Squid's number (for running 2 or more squids with different ports)\n"
       "-д x,y\t signal to running copy to set debug section x to level y and exit.\n"
       "-p uClass,delta\t signal to running copy to set priority to uClass\n"
       "   (1-Idle,2-Regular,3-TimeCritical,4-FixedHigh[Default]),delta[-31,...31]\n"

#if HAVE_SYSLOG
       "-s       Enable logging to syslog.\n"
#endif
       "-u port  Specify ICP port number (default: %d), disable with 0.\n"
       "-v\t Print version.\n"
       "-z\t Create swap directories\n"
       "-C\t Do not catch fatal signals.\n"
       "-D\t Disable initial DNS tests.\n"
       "-F\t Don't serve any requests until store is rebuilt.\n"
       "-H MaxFD set max number of file descriptors/handles\n"
       "-N\t No daemon mode.\n"
       "-R\t Do not set REUSEADDR on port.\n"
       "-S\t Double-check swap during rebuild.\n"
       "-V\t Virtual host httpd-accelerator.\n"
       "-X\t Force full debugging.\n"
       "-Y\t Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
       appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
      fprintf(stderr,"Squid Cache: Version %s\n", version_string);
    exit(1);
}



static void
mainParseOptions(int argc, char *argv[])
{
    extern char *optarg;
    int c;

#if HAVE_SYSLOG
    while ((c = getopt(argc, argv, "CDFH:NRSVYXa:d:f:hk:m::n:su:vz?")) != -1)
#else
    while ((c = getopt(argc, argv, "CDFH:NRSVYXa:d:f:hk:m::n:p:u:vzд:?")) != -1)
#endif

    {
      switch (c) {
       case 'C':
           opt_catch_signals = 0;
           break;
       case 'D':
           opt_dns_tests = 0;
           break;
       case 'F':
           opt_foreground_rebuild = 1;
           break;
       case 'H':
        {  int maxfd;
//       "-H MaxFD set max number of file descriptors/handels\n"
           maxfd = atoi(optarg);
           if(maxfd  > 0x10000) maxfd  = 0x10000;
           if(squid_fd_table.squid_fdeArrayRealloc(maxfd) == NULL)
           {
               fatal("NO memory for squid_fdeArrayRealloc");
           }
           Squid_MaxFD = maxfd;
        }
           break;
       case 'N':
           opt_no_daemon = 1;
           break;
       case 'R':
           opt_reuseaddr = 0;
           break;
       case 'S':
           opt_store_doublecheck = 1;
           break;
       case 'V':
           vhost_mode = 1;
           break;
       case 'X':
           /* force full debugging */
           sigusr2_handle(SIGUSR2);
           break;
       case 'Y':
           opt_reload_hit_only = 1;
           break;
       case 'a':
//2.6
//EK           parse_sockaddr_in_list_token(&Config.Sockaddr.http, optarg);
//2.5
    httpPortNumOverride = atoi(optarg);

           break;
       case 'd':
           opt_debug_stderr = atoi(optarg);
           break;
       case 'f':
           xfree(ConfigFile);
           ConfigFile = xstrdup(optarg);
           break;
       case 'h':
           usage();
           break;
       case 'k':
           if ((int) strlen(optarg) < 1)
               usage();
           if (!strncmp(optarg, "reconfigure", strlen(optarg)))
               opt_send_signal = S_RECONFIGURE;
           else if (!strncmp(optarg, "rotate", strlen(optarg)))
                 opt_send_signal = S_ROTATE;
           else if (!strncmp(optarg, "debug", strlen(optarg)))
               opt_send_signal = S_DEBUG;
           else if (!strncmp(optarg, "shutdown", strlen(optarg)))
               opt_send_signal = S_SHUTDOWN;
           else if (!strncmp(optarg, "interrupt", strlen(optarg)))
               opt_send_signal = SIGINT;
           else if (!strncmp(optarg, "kill", strlen(optarg)))
               opt_send_signal = S_KILL;
           else if (!strncmp(optarg, "check", strlen(optarg)))
               opt_send_signal = 0;    /* SIGNULL */
           else if (!strncmp(optarg, "parse", strlen(optarg)))
               opt_parse_cfg_only = 1;         /* parse cfg file only */
           else
               usage();
           break;
       case 'д':
               opt_send_signal = S_DEBUG;
              strcpy(opt_debug_str,optarg);
           break;
       case 'p':
              opt_send_signal = S_PRIORITY;
              strcpy(opt_debug_str,optarg);
          break;
       case 'm':
           if (optarg) {
#if MALLOC_DBG
               malloc_debug_level = atoi(optarg);
               /* NOTREACHED */
               break;
#else
               fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
               /* NOTREACHED */
#endif
           } else {
#if XMALLOC_TRACE
               xmalloc_trace = !xmalloc_trace;
#else
               fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
#endif
           }
       case 'n':
           Config.SquidNum = atoi(optarg);

#if HAVE_SYSLOG
       case 's':
           opt_syslog_enable = 1;
           break;
#endif
       case 'u':
           icpPortNumOverride = atoi(optarg);
           if (icpPortNumOverride < 0)
               icpPortNumOverride = 0;
           break;
       case 'v':
           printf("Squid Cache: Version %s\n", version_string);
           printf("\t     Compiled with: ");

#ifdef DELAY_POOLS
           printf("Delay pools, ");
#endif
#if USE_ICMP
           printf("ICMP, ");
#endif
           printf("%i file descriptors\n", SQUID_MAXFD);
#ifdef TCPV40HDRS
           printf("\t     Compiled for 16bit TCP/IP stack\n");
#else
           printf("\t     Compiled for 32bit TCP/IP stack\n");
#endif
//??    printf("\t     configure options: %s\n", SQUID_CONFIGURE_OPTIONS);

           exit(0);
           /* NOTREACHED */
       case 'z':
           opt_create_swap_dirs = 1;
           break;
       case '?':
       default:
           usage();
           break;
       }
    }

}


/* ARGSUSED */
SIGHDLR
rotate_logs(int sig)
{
    do_rotate = 1;
#if !HAVE_SIGACTION
    signal(sig, (_SigFunc) rotate_logs);
#endif

}

#if ALARM_UPDATES_TIME
static void
time_tick(int sig)
{
    getCurrentTime();
    alarm(1);
#if !HAVE_SIGACTION
    signal(sig, time_tick);
#endif
}

#endif

/* ARGSUSED */
static SIGHDLR
reconfigure(int sig)
{
    do_reconfigure = 1;
#if !HAVE_SIGACTION
    signal(sig, (_SigFunc)reconfigure);
#endif
}


void
shut_down(int sig)
{
    do_shutdown = sig == SIGINT ? -1 : 1;
    debug(0, 0) ("shut_down, sig=%d\n", sig);

#ifdef KILL_PARENT_OPT
    if (getppid() > 1) {
       debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
       kill(getppid(), sig);
    }
#endif
#if SA_RESETHAND == 0
    signal(SIGTERM, SIG_DFL);
    signal(SIGINT, SIG_DFL);
#endif
}


static void
serverConnectionsOpen(void)
{
    clientOpenListenSockets();
    icpConnectionsOpen();
#if USE_HTCP
    htcpInit();
#endif
#ifdef SQUID_SNMP
    snmpConnectionOpen();
#endif
#if USE_WCCP
    wccpConnectionOpen();
#endif
    clientdbInit();
    icmpOpen();
    netdbInit();
    asnInit();
    peerSelectInit();
#if USE_CARP
    carpInit();
#endif
}


void
serverConnectionsClose(void)
{
    assert(shutting_down || reconfiguring);
    clientHttpConnectionsClose();
    icpConnectionShutdown();
#if USE_HTCP
    htcpSocketShutdown();
#endif
    icmpClose();
#ifdef SQUID_SNMP
    snmpConnectionShutdown();
#endif
#if USE_WCCP
    wccpConnectionShutdown();
#endif
    asnFreeMemory();
}


static void
mainReconfigure(void)
{
#ifdef _SQUID_OS2_
    fprintf(debug_log,"\n");
#endif
    SquidKillAllChilds();

    debug(1, 0) ("Restarting Squid Cache (version %s)...\n", version_string);
    reconfiguring = 1;
    /* Already called serverConnectionsClose and ipcacheShutdownServers() */
    serverConnectionsClose();
    icpConnectionClose();
#if USE_HTCP
    htcpSocketClose();
#endif
#ifdef SQUID_SNMP
    snmpConnectionClose();
#endif
#if USE_WCCP
    wccpConnectionClose();
#endif
#if USE_DNSSERVERS
    dnsShutdown();
#else
    idnsShutdown();
#endif
    redirectShutdown();
    authenticateShutdown();
    externalAclShutdown();
    storeDirCloseSwapLogs();

    storeLogClose(); //?
    accessLogClose();//?
    useragentLogClose();//?
    refererCloseLog();//?

    errorClean();
    parseConfigFile(ConfigFile);
    _db_init(Config.Log.log, Config.debugOptions);
    ipcache_restart();         /* clear stuck entries */
    authenticateUserCacheRestart();    /* clear stuck ACL entries */
    fqdncache_restart();       /* sigh, fqdncache too */
    parseEtcHosts();
    errorInitialize();         /* reload error pages */
    accessLogInit(); //?
    storeLogOpen();//?
    useragentOpenLog(); //?
    refererOpenLog(); //?
#if USE_DNSSERVERS
    dnsInit();
#else
    idnsInit();
#endif
    redirectInit();
    authenticateInit(&Config.authConfig);
    externalAclInit();

#if USE_WCCP
    wccpInit();
#endif
    serverConnectionsOpen();
    if (theOutIcpConnection >= 0) {
       if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
           neighbors_open(theOutIcpConnection);
       else
           debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
    }
    storeDirOpenSwapLogs();
    mimeInit(Config.mimeTablePathname);
    writePidFile();            /* write PID file */
    debug(1, 1) ("Ready to serve requests.\n");
    reconfiguring = 0;

}


static void
mainRotate(void)
{
/*
    icmpClose();
#if USE_DNSSERVERS
    dnsShutdown();
#endif
    SquidKillAllChilds();

    redirectShutdown();
    authenticateShutdown();
    externalAclShutdown();
*/
    _db_rotate_log();          /* cache.log */
//    storeDirWriteCleanLogs(1);
    storeLogRotate();          /* store.log */
    accessLogRotate();         /* access.log */
    useragentRotateLog();      /* useragent.log */
    refererRotateLog();                /* referer.log */
#if WIP_FWD_LOG
    fwdLogRotate();
#endif
/*
    icmpOpen();
#if USE_DNSSERVERS
    dnsInit();
#endif
    redirectInit();
    authenticateInit(&Config.authConfig);
    externalAclInit();
*/
}




static void
mainInitialize(void)
{
    int rc;

    /* chroot if configured to run inside chroot */
    if (Config.chroot_dir && chroot(Config.chroot_dir)) {
       fatal("failed to chroot");
    }
    if (opt_catch_signals) {
//EK for debug       squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
       squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
    }
    squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
    squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);

    assert(Config.Sockaddr.http);
    if (httpPortNumOverride != 1)
        Config.Sockaddr.http->s.sin_port = htons(httpPortNumOverride);

    if (icpPortNumOverride != 1)
       Config.Port.icp = (u_short) icpPortNumOverride;

    _db_init(Config.Log.log, Config.debugOptions);
//  fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
    rc = squid_fd_table.open(index_fd_debug_log[0],fileno(debug_log), FD_LOG,  Config.Log.log);

#if MEM_GEN_TRACE
    log_trace_init("/tmp/squid.alloc");
#endif
#ifdef _SQUID_OS2_
    fprintf(debug_log,"\n\n");
#endif
    debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
       version_string,
       CONFIG_HOST_TYPE);
    debug(1, 1) ("Process ID %d\n", (int) getpid());
    debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);

/******/
    if (!configured_once)
       disk_init();            /* disk_init must go before ipcache_init() */
    ipcache_init();
    fqdncache_init();
    parseEtcHosts();

#if USE_DNSSERVERS
    dnsInit();
#else
    idnsInit();
#endif
    redirectInit();
    authenticateInit(&Config.authConfig);
    externalAclInit();
    useragentOpenLog();
    refererOpenLog();

    httpHeaderInitModule();    /* must go before any header processing (e.g. the one in errorInitialize) */
    httpReplyInitModule();     /* must go before accepting replies */
    errorInitialize();
    accessLogInit();

#if USE_IDENT
    identInit();
#endif
#ifdef SQUID_SNMP
    snmpInit();
#endif
#if MALLOC_DBG
    malloc_debug(0, malloc_debug_level);
#endif

    if (!configured_once) {
#if USE_UNLINKD
       unlinkdInit();
#endif
       urlInitialize();
       cachemgrInit();
       statInit();
       storeInit();
       /* after this point we want to see the mallinfo() output */
       do_mallinfo = 1;
// { int tmp = opt_debug_stderr;
//   if(opt_debug_stderr > 1)  opt_debug_stderr  = 1;
       mimeInit(Config.mimeTablePathname);
//   opt_debug_stderr = tmp;
// }
       pconnInit();
       refreshInit();
#if DELAY_POOLS
       delayPoolsInit();
#endif
       fwdInit();
    }
#if USE_WCCP
    wccpInit();
#endif

    serverConnectionsOpen();
    if (theOutIcpConnection >= 0) {
       if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
           neighbors_open(theOutIcpConnection);
       else
           debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
    }
#ifndef _SQUID_OS2_
    if (Config.chroot_dir)
       no_suid();
#endif
    if (!configured_once)
       writePidFile();         /* write PID file */

#ifdef _SQUID_LINUX_THREADS_
    squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
    squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
#else
    squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
    squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
#endif
    squid_signal(SIGHUP, reconfigure, SA_RESTART);
    squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
    squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
#if ALARM_UPDATES_TIME
    squid_signal(SIGALRM, time_tick, SA_RESTART);
    alarm(1);
#endif
    memCheckInit();
    debug(1, 1) ("Ready to serve requests.\n");
    if (!configured_once) {
       eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
       if (Config.onoff.announce)
           eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
       eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
       eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
//EK2.6       eventAdd("memPoolCleanIdlePools", memPoolCleanIdlePools, NULL, 15.0, 1);

    }
    configured_once = 1;

}


/***********/
/*  MAin.c */
/***********/
int
main(int argc, char **argv)
{
    int errcount = 0, t, tShutdown = 0;
    int n,rc;                     /* # of GC'd objects */
    int loop_delay;
#ifndef _SQUID_OS2_
    mode_t oldmask;
#endif

#ifdef DEBUG_SPY
   InitDebugSpy(DEBUG_SPY);
   atexit(CloseDebugSpy);
#endif

#ifdef _SQUID_OS2_

{ PPIB pib;
  PTIB tib;
  printf("In console\n");
  DosGetInfoBlocks(&tib, &pib);
  SquidMainTID = tib->tib_ptib2->tib2_ultid;         /*  Current thread identifier. */
  //=1
//  printf("Squid main TID=%i\n",SquidMainTID);
}

     atexit(CloseAllFHatExit);
    _tzset();
    n = OS2SetRelMaxFH(0); /* спрашиваем выделенное число файловых хендлов */
    if(n < 50) OS2SetRelMaxFH(50-n); /* устанавливаем 50 файловых хендлов  */

#endif
    debug_log = stderr;
    if (FD_SETSIZE < Squid_MaxFD)
       Squid_MaxFD = FD_SETSIZE;


    /* call mallopt() before anything else */
#if HAVE_MALLOPT
#ifdef M_GRAIN
    /* Round up all sizes to a multiple of this */
    mallopt(M_GRAIN, 16);
#endif
#ifdef M_MXFAST
    /* biggest size that is considered a small block */
    mallopt(M_MXFAST, 256);
#endif
#ifdef M_NBLKS
    /* allocate this many small blocks at once */
    mallopt(M_NLBLKS, 32);
#endif
#endif /* HAVE_MALLOPT */

#ifndef _SQUID_OS2_

    /*
     * The plan here is to set the umask to 007 (deny others for
     * read,write,execute), but only if the umask is not already
     * set.  Unfortunately, there is no way to get the current
     * umask value without setting it.
     */
    oldmask = umask(S_IRWXO);
    if (oldmask)
       umask(oldmask);
#endif
    memset(&local_addr, '\0', sizeof(struct in_addr));
    safe_inet_addr(localhost, &local_addr);
    memset(&any_addr, '\0', sizeof(struct in_addr));
    safe_inet_addr("0.0.0.0", &any_addr);
    memset(&no_addr, '\0', sizeof(struct in_addr));
    safe_inet_addr("255.255.255.255", &no_addr);
    squid_srandom(time(NULL));

    getCurrentTime();
    squid_start = current_time;
    failure_notify = fatal_dump;

    mainParseOptions(argc, argv);


    if (ConfigFile == NULL)
       ConfigFile = DefaultConfigFileName();
    opt_no_daemon = 1;
/* Under OS/2 DETACH command must be used for starting in "daemon mode" */
    setServerPriority();


    /* parse configuration file
     * note: in "normal" case this used to be called from mainInitialize() */
    {
       int parse_err;
       if (!ConfigFile)
           ConfigFile = xstrdup(DefaultConfigFile);
       assert(!configured_once);
#if USE_LEAKFINDER
       leakInit();
#endif
       memInit();
       cbdataInit();

       eventInit();            /* eventInit() is required for config parsing */
       storeFsInit();          /* required for config parsing */
       authenticateSchemeInit();       /* required for config parsign */
       parse_err = parseConfigFile(ConfigFile);

       if (opt_parse_cfg_only)
           return parse_err;
    }

    SquidServerMode = 0;
    rc = checkRunningPid();
    if(!rc)  SquidServerMode = 1;

    if (-1 == opt_send_signal)
    {  if (rc)
       {  debug(0, 0) ("WARNING: Squid process %d is already running!\n", Config.SquidNum);
           exit(1);
       }
    } else {
       if (!rc)
       {  debug(0, 0) ("WARNING: Hmm...  Squid process %d is NOT running!\n", Config.SquidNum);
           exit(1);
       }
    }
   if(SquidServerMode)
   {  startServerThreads();
   }

#if TEST_ACCESS
    comm_init();
    comm_select_init();
    mainInitialize();
    test_access();
    return 0;
#endif

    /* send signal to running copy and exit */
    if (opt_send_signal != -1) {
       sendSignal();
       /* NOTREACHED */
    }
    if (opt_create_swap_dirs) {
       debug(0, 0) ("Creating Swap Directories\n");
       storeCreateSwapDirectories();
       return 0;
    }


    if (!opt_no_daemon)
       watch_child(argv);

    setMaxFD();


//    if (opt_catch_signals)
//       for (n = Squid_MaxFD; n > 2; n--)
//           close(n);

    /* init comm module */
    comm_init();
    comm_select_init();


    if (opt_no_daemon) {
       /* we have to init fdstat here. */
    rc = squid_fd_table.open(index_fd_debug_log[1],0, FD_LOG, "stdin");
    rc = squid_fd_table.open(index_fd_debug_log[2],1, FD_LOG, "stdout");
    rc = squid_fd_table.open(index_fd_debug_log[3],2, FD_LOG, "stderr");
//       fd_open(0, FD_LOG, "stdin");
//       fd_open(1, FD_LOG, "stdout");
//       fd_open(2, FD_LOG, "stderr");
    }

    mainInitialize();

    debug(50, 0) ("SQUID_WatchDog:_beginthread call\n" );
    rc = _beginthread(SQUID_WatchDog,NULL, STACK_SIZE,NULL);
    debug(50, 0) ("SQUID_WatchDog:_beginthread id=%i\n",rc );


    /* main loop */
    for (;;) {
       if (do_reconfigure) {
           mainReconfigure();
           do_reconfigure = 0;
       } else if (do_rotate) {
           mainRotate();
           do_rotate = 0;
       } else if (do_shutdown) {
           time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
           debug(1, 1) ("Preparing for shutdown after %d requests\n",
               statCounter.client_http.requests);
           debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
               (int) wait);
           do_shutdown = 0;
           shutting_down = 1;
           serverConnectionsClose();
           eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
           tShutdown = clock();
       } else if(shutting_down && Config.onoff.UseANSI_stdout) {
           t = clock() - tShutdown;
           t /= 1000;
           if(opt_debug_stderr <= 5 && t > 3 )
           {  fprintf(stderr, "\r" WARNING_COLOR "%i " NORMAL_COLOR "\r", Config.shutdownLifetime - t);
              fflush(stderr);
           }

       }
       eventRun();

       if ((loop_delay = eventNextTime()) < 0)
           loop_delay = 0;
       switch (comm_select(loop_delay)) {
       case COMM_OK:
           errcount = 0;       /* reset if successful */
           break;
       case COMM_ERROR:
           errcount++;
           debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
           if (errcount == 10)
               fatal_dump("Select Loop failed!");
           break;
       case COMM_TIMEOUT:
           break;
       case COMM_SHUTDOWN:
           SquidShutdown(NULL);
           break;
       default:
           fatal_dump("MAIN: Internal error -- this should never happen.");
           break;
       }
    }
    /* NOTREACHED */
    return 0;
}



static void
sendSignal(void)
{
    pid_t pid=0;
    debug_log = stderr;

     if (SendSignalToWorkindSquid(opt_send_signal,opt_debug_str))
     {      fprintf(stderr, "%s: ERROR: Could not send ", appname);
             fprintf(stderr, "signal %d to process %d: %s\n",
               opt_send_signal, (int) pid, xstdio_strerror());
           exit(1);
       }

    /* signal successfully sent */
    exit(0);
}

/*
 * This function is run when Squid is in daemon mode, just
 * before the parent forks and starts up the child process.
 * It can be used for admin-specific tasks, such as notifying
 * someone that Squid is (re)started.
 */
static void
mainStartScript(const char *prog)
{
    char script[SQUID_MAXPATHLEN];
    char *t;
    size_t sl = 0;
    pid_t cpid;
    pid_t rpid;
    xstrncpy(script, prog, MAXPATHLEN);
    t = strrchr(script, '/');
    if (t) {
       *(++t) = '\0';
       sl = strlen(script);
    }
    xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
    if ((cpid = fork()) == 0) {
       /* child */
       execl(script, (char *)squid_start_script, 0);

       _exit(0);
/* временная затычка для выкидывания waitpid'а */
#ifndef _SQUID_OS2_
    } else {
       do {
#ifdef _SQUID_NEXT_
           union wait status;
           rpid = wait3(&status, 0, NULL);
#else
           int status;
           rpid = waitpid(-1, &status, 0);
#endif
       } while (rpid != cpid);
#endif // _SQUID_OS2_
    }
}

char SQUIDmutexName[20]; /* Semaphore name */
HMTX SQUID_hmtx     = NULLHANDLE; /* Mutex semaphore handle */
class NPipe SQUID_pipe[MAX_NUM_THREADS];
struct LS_threads
{
   volatile int semaphore;    // семафор для блокировки одновременного доступа к остальным полям
   int num;          // число ниток
   int next_free;    // следующая свободная
   int working;      // =0 на старте, =1 после появления первого живого клиента (защелка)
   int Nclients;     // число живых клиентов
   int thread_id[MAX_NUM_THREADS]; // id'ы ниток
//   int hits_total[MAX_NUM_THREADS]; // запросов всего по ниткам
//   int hits_min  [MAX_NUM_THREADS]; // запросов за минуту по ниткам
//   int hits_hour [MAX_NUM_THREADS]; // запросов за час    по ниткам
   int state [MAX_NUM_THREADS];     // состояние нитки: 0-свободно, 1 - занято
};

struct LS_threads  LSthreads = { 0,0,0,0,0 };


//Create mutex semaphore and check for running copy
static int
checkRunningPid(void)
{   int rc;
    char snum[10];
    snprintf(SQUIDmutexName,sizeof(SQUIDmutexName),"\\SEM32\\SQUID2_%i",Config.SquidNum);
    errno = 0;

    rc = DosCreateMutexSem(SQUIDmutexName,      /* Semaphore name */
                           &SQUID_hmtx, 0, FALSE);       /* Handle returned */
    if (rc != NO_ERROR)
    {
       if(rc == ERROR_DUPLICATE_NAME)
       {  return 1;
       }
       else
          debug(0, 0) ("WARNING: DosCreateMutexSem error: %s\n", xstdio_strerror());
       return -1;
     }

return 0;

/*
    pid_t pid;
    debug_log = stderr;

    pid = readPidFile();
    if (pid < 2)
       return 0;
    if (kill(pid, 0) < 0)
       return 0;
    debug(0, 0) ("Squid is already running!  Process ID %d\n", pid);
    return 1;
*/
}

static void
watch_child(char *argv[])
{

#ifndef _SQUID_OS2_
    char *prog;
    int failcount = 0;
    time_t start;
    time_t stop;
#ifdef _SQUID_NEXT_
    union wait status;
#else
    int status;
#endif
    pid_t pid;
    int i;
    int nullfd;
    if (*(argv[0]) == '(')
       return;
    openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
    if ((pid = fork()) < 0)
       syslog(LOG_ALERT, "fork failed: %s", xstdio_strerror());
    else if (pid > 0)
       exit(0);
    if (setsid() < 0)
       syslog(LOG_ALERT, "setsid failed: %s", xstdio_strerror());
    closelog();
#ifdef TIOCNOTTY

#ifdef _SQUID____OS2_
    if ((i = open("/dev/tty", O_RDWR | O_TEXT|O_NOINHERIT)) >= 0) {
#else
    if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
#endif
       ioctl(i, TIOCNOTTY, NULL);
       close(i);
    }
#endif


    /*
     * RBCOLLINS - if cygwin stackdumps when squid is run without
     * -N, check the cygwin1.dll version, it needs to be AT LEAST
     * 1.1.3.  execvp had a bit overflow error in a loop..
     */
    /* Connect stdio to /dev/null in daemon mode */
    nullfd = open("/dev/null", O_RDWR | O_TEXT);
    if (nullfd < 0)
       fatalf("/dev/null: %s\n", xstrerror());
    dup2(nullfd, 0);
    if (opt_debug_stderr < 0) {
       dup2(nullfd, 1);
       dup2(nullfd, 2);
    }
    /* Close all else */
    for (i = 3; i < Squid_MaxFD; i++)
       close(i);
    for (;;) {
       mainStartScript(argv[0]);
       if ((pid = fork()) == 0) {
           /* child */
           openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
           prog = xstrdup(argv[0]);
           argv[0] = xstrdup("(squid)");
           execvp(prog, argv);
           syslog(LOG_ALERT, "execvp failed: %s", xstdio_strerror());
       }
       /* parent */
       openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
       syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
       time(&start);
       squid_signal(SIGINT, SIG_IGN, SA_RESTART);
#ifdef _SQUID_NEXT_
       pid = wait3(&status, 0, NULL);
#else
       pid = waitpid(-1, &status, 0);
#endif
       time(&stop);
       if (WIFEXITED(status)) {
           syslog(LOG_NOTICE,
               "Squid Parent: child process %d exited with status %d",
               pid, WEXITSTATUS(status));
       } else if (WIFSIGNALED(status)) {
           syslog(LOG_NOTICE,
               "Squid Parent: child process %d exited due to signal %d",
               pid, WTERMSIG(status));
       } else {
           syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
       }
       if (stop - start < 10)
           failcount++;
       else
           failcount = 0;
       if (failcount == 5) {
           syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
           exit(1);
       }
       if (WIFEXITED(status))
           if (WEXITSTATUS(status) == 0)
               exit(0);
       if (WIFSIGNALED(status)) {
           switch (WTERMSIG(status)) {
           case SIGKILL:
               exit(0);
               break;
           default:
               break;
           }
       }
       squid_signal(SIGINT, SIG_DFL, SA_RESTART);
       sleep(3);
    }
    /* NOTREACHED */
#endif /* _SQUID_OS2_ */


}



static void
SquidShutdown(void *unused)
{
    debug(1, 1) ("Shutting down...\n");
#if USE_DNSSERVERS
           dnsShutdown();
#else
           idnsShutdown();
#endif
    redirectShutdown();
    externalAclShutdown();
    icpConnectionClose();
#if USE_HTCP
    htcpSocketClose();
#endif
#ifdef SQUID_SNMP
    snmpConnectionClose();
#endif
#if USE_WCCP
    wccpConnectionClose();
#endif
    releaseServerSockets();
    commCloseAllSockets();
    authenticateShutdown();
#if USE_UNLINKD
    unlinkdClose();
#endif
    storeDirSync();            /* Flush pending object writes/unlinks */
    storeDirWriteCleanLogs(0);
    PrintRusage();
    dumpMallocStats();
    storeDirSync();            /* Flush log writes */
    storeLogClose();
    accessLogClose();
    useragentLogClose();
    refererCloseLog();
#if WIP_FWD_LOG
    fwdUninit();
#endif
    storeDirSync();            /* Flush log close */
#if PURIFY || XMALLOC_TRACE
    storeFsDone();
    configFreeMemory();
    storeFreeMemory();
    /*stmemFreeMemory(); */
    netdbFreeMemory();
    ipcacheFreeMemory();
    fqdncacheFreeMemory();
    asnFreeMemory();
    clientdbFreeMemory();
    httpHeaderCleanModule();
    statFreeMemory();
    eventFreeMemory();
    mimeFreeMemory();
    errorClean();
#endif
#if !XMALLOC_TRACE
    if (opt_no_daemon) {
       file_close(0);
       file_close(1);
       file_close(2);
    }
#endif
    fdDumpOpen();

    SquidKillAllChilds();
    squid_fd_table.closeAll();

    fdFreeMemory();
    memClean();
#if XMALLOC_TRACE
    xmalloc_find_leaks();
    debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
#endif
#if MEM_GEN_TRACE
    log_trace_done();
#endif

    if (Config.pidFilename && strcmp(Config.pidFilename, "none")) {
#ifndef _SQUID_OS2_
       enter_suid();
#endif
       safeunlink(Config.pidFilename, 0);
#ifndef _SQUID_OS2_
       leave_suid();
#endif
    }
    debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
       version_string);
    if (debug_log)
       fclose(debug_log);
    exit(0);
}
void _Optlink CloseAllFHatExit(void)
{
    squid_fd_table.closeAll();
}

/*******************************************/
int SendSignalToWorkindSquid(int opt_send_signal, char *senddata)
{   int i,ii,rep,rc, ncmd, data;
    char PipeName[256];
    class NPipe SQUIDpipe;
/* 1st - connect to proper PIPE */
   for(rep=0,i=0;i<MAX_NUM_PIPES*2,rep<40+MAX_NUM_PIPES;i++)
   {  ii = i % MAX_NUM_PIPES;
      snprintf(PipeName,256,"\\PIPE\\SQUID2_%i_%i",Config.SquidNum ,ii);
      SQUIDpipe = NPipe(PipeName,CLIENT_MODE,1,0);

      rc = SQUIDpipe.Open();
/* */

      if(rc == ERROR_PIPE_BUSY)
               continue;
      if(rc == ERROR_PATH_NOT_FOUND)
      {  rep++;
         DosSleep(1+rep);
         //i--;
         if(rep == MAX_NUM_PIPES) i = -1;
         continue;
      }
      if(rc)
      { // printf("Error open pipe rc=%i",rc);
        // sgLogError("Error open pipe rc=%i, Exitting",rc);
        // if(rc == ERROR_INVALID_PARAMETER) printf("(Hедопустимый паpаметp");
         debug(0, 0) ("SendSignalToWorkindSquid:WARNING: Error connecting pipe %s: %s\n",PipeName,xstdio_strerror());
         exit(1);
      }
      break;
    }

    if(SQUIDpipe.Hpipe < 0)
    {  fatal("SendSignalToWorkindSquid: Can't open pipe(s), Exitting");
       exit(2);
    }
    debug(0, 0) ("SendSignalToWorkindSquid:Open pipe %s Ok\n",PipeName);

//fprintf(fpAlt,"Hpipe=%x, stdin=%x,stdout%x\n",SQDRpipe.Hpipe,fileno(stdin),fileno(stdout));

    rc = SQUIDpipe.HandShake();
    if(rc ==  HAND_SHAKE_ERROR)
    {   debug(0, 0) ("WARNING: Error HandShake pipe %s: %s\n",PipeName,xstdio_strerror());
        exit(1);
    }
    debug(0, 1) ("HandShake pipe: %s Ok\n",PipeName);
    rc = SQUIDpipe.SendCmdToServer(1, opt_send_signal); // команда 1 - послать  opt_send_signal
    if(rc)
    {   debug(0, 0) ("WARNING: SendCmdToServer error %i\n",rc);
        exit(1);
    }
    rc = SQUIDpipe.RecvCmdFromClient(&ncmd,&data);
    if(rc)
    {   debug(0, 0) ("WARNING: RecvCmdFromClient error %i\n",rc);
        exit(1);
    }
    if(ncmd != 1)
        debug(0, 0) ("WARNING: server answer error (%i != %i)\n",ncmd,1);
    if(opt_send_signal  == S_DEBUG || opt_send_signal  == S_PRIORITY)
    {  int l;
       l = 0;
      if(senddata && strlen(senddata) > 0)
              l = strlen(senddata);
      rc = SQUIDpipe.SendCmdToServer(2, l); // команда 2 - послать  данные
      if(l>0 && !rc)
      {  rc = SQUIDpipe.SendDataToServer(senddata, l);
      }

    }
    rc = SQUIDpipe.Close();
        debug(0, 1) ("Pipe close rc %i\n",rc);

    return 0;
}
/*******************************************/
int ThreadStart = 0;

void _Optlink SQUID_ClientWork(void *param)
{   int i,rc, threadNum,id,idd;
    int ncmd,data,l;
    char PipeName[256];
    char str[512];
    char buf[MAX_BUF], bufout[MAX_BUF];

    _control87(EM_UNDERFLOW,EM_UNDERFLOW);

   while(__lxchg(&LSthreads.semaphore, LOCKED))
                                       DosSleep(1);
    threadNum =  LSthreads.next_free;
    debug(0, 2) ("SQUID_ClientWork: Pipe creating %i (%i)\n",threadNum,LSthreads.thread_id[threadNum]);
    fflush(stdout);
    ThreadStart++;
   DosSleep(10);

   __lxchg(&LSthreads.semaphore, UNLOCKED);
   do
   { DosSleep(1);
   } while(ThreadStart != 3);

//    if(param)
//           threadNum = * ((int *)param);

    DosSleep(10);

    snprintf(PipeName,256,"\\PIPE\\SQUID2_%i_%i",Config.SquidNum ,threadNum);

    SQUID_pipe[threadNum] = NPipe(PipeName,SERVER_MODE,MAX_NUM_THREADS,threadNum);
    rc = SQUID_pipe[threadNum].Create();
    if(rc == ERROR_TOO_MANY_OPEN_FILES)
    {     rc = OS2SetRelMaxFH(8);
          rc = SQUID_pipe[threadNum].Create();
    }

    if(rc)
    {  snprintf(str,256, "Error pipe creating  %s rc=%i",PipeName,rc);
       if(rc == ERROR_INVALID_PARAMETER)
                   strcat(str,"(INVALID PARAMETER)");
       else
          if (rc == ERROR_PIPE_BUSY)
                   strcat(str,"(PIPE_BUSY)");
       if (rc == ERROR_PIPE_BUSY)
       {    debug(0, 0) ("WARNING: SQUID_ClientWork: %s\n",str);
            goto ENDTHREAD;
       }
       fatal(str);
    }
    debug(0, 2) ("SQUID_ClientWork: Pipe create %s %x %x\n",PipeName, threadNum ,SQUID_pipe[threadNum].Hpipe);
    debug(0, 2) ("SQUID_ClientWork: Pipe create Ok %s\n",PipeName);
    fflush(stdout);

    rc = SQUID_pipe[threadNum].Connect();
    if(rc)
    {   debug(0, 0) ("WARNING: Error connecting pipe %s: %s\n",PipeName,xstdio_strerror());
        goto ENDTHREAD;
    }
    debug(0, 2) ("Connecting pipe: %s Ok\n",PipeName);
    rc = SQUID_pipe[threadNum].HandShake();
    if(rc)
    {   debug(0, 0) ("WARNING: Error HandShake pipe %s: %s\n",PipeName,xstdio_strerror());
        goto ENDTHREAD;
    }
    debug(0, 2) ("HandShake pipe: %s Ok\n",PipeName);
    fflush(stdout);

/***********/
   for(i = 0; i < MAX_NUM_THREADS; i++)
      {
//    debug(0, 0) ("(%i %i)",i,LSthreads.thread_id[i]);
         if(LSthreads.thread_id[i] == -1)
         {     break;
         }
     }
   idd = LSthreads.next_free;
//    debug(0, 0) ("idd=%i",idd);
   ThreadStart = 1;

   debug(50, 0) ("SQUID_ClientWork:_beginthread\n" );
   id = _beginthread(SQUID_ClientWork,NULL, STACK_SIZE,&idd);
   debug(50, 0) ("SQUID_ClientWork:_beginthread id=%i\n",id );

   do
   { DosSleep(1);
   } while(ThreadStart == 1);

   while(__lxchg(&LSthreads.semaphore, LOCKED)) DosSleep(1);

   LSthreads.Nclients++;     // число живых клиентов
   LSthreads.working = 1;    // =0 на старте, =1 после появления первого живого клиента (защелка)
   LSthreads.num++;
   LSthreads.thread_id[LSthreads.next_free] = id;


   for(i = 0; i < MAX_NUM_THREADS; i++)
      {
// l = (i + LSthreads.next_free)%MAX_NUM_THREADS;
//    debug(0, 0) ("[%i %i]",i,LSthreads.thread_id[i]);
         if(LSthreads.thread_id[i] == -1)
         {     LSthreads.next_free = i;
               break;
         }
      }

   ThreadStart = 3;
   __lxchg(&LSthreads.semaphore, UNLOCKED);
    LSthreads.state[threadNum]=0;
DosSleep(10);
    debug(0, 2) ("SQUID_ClientWork: Pipe working %s\n",PipeName);
/*****************/
   do
   {  LSthreads.state[threadNum]=0;
      rc = SQUID_pipe[threadNum].RecvCmdFromClient(&ncmd,&data);
      if(rc)
      {  if(rc == -1)
         {  rc = SQUID_pipe[threadNum].QueryState();
            if(rc == ERROR_BAD_PIPE || rc == ERROR_PIPE_NOT_CONNECTED)
                                  break; // клиент подох ??
         }
         debug(0, 0) ("WARNING: SQUID_ClientWork: RecvCmdFromClient error %x %s\n",rc,xstdio_strerror());
         goto ENDTHREAD;
      }
      LSthreads.state[threadNum]=1;

      switch(ncmd)
      {  case 1:
            debug(0, 2) ("SQUID_ClientWork: Get ncmd %x %x\n",ncmd, data);
             rc=SQUID_pipe[threadNum].SendCmdToServer(ncmd,data);
             switch(data)
             {  case S_SHUTDOWN:
                 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
//            debug(0, 0) ("squid_signal:\n");
                 DosSleep(100);
                  rc = raise(SIGTERM);
//            debug(0, 0) ("raise: rc =%x %s\n",rc,xstdio_strerror());
                  break;
               case S_RECONFIGURE:
                       do_reconfigure = 1;
                  break;
               case S_ROTATE:
                       do_rotate = 1;
                   break;

               case S_PRIORITY:
                 {   int l;
                     rc = SQUID_pipe[threadNum].RecvCmdFromClient(&ncmd,&data);
                     if(rc)
                     {  if(rc == -1)
                         {  rc = SQUID_pipe[threadNum].QueryState();
                            if(rc == ERROR_BAD_PIPE || rc == ERROR_PIPE_NOT_CONNECTED)
                                 break; // клиент подох ??
                         }
                         debug(0, 0) ("WARNING: SQUID_ClientWork: RecvCmdFromClient error %x %s\n",rc,xstdio_strerror());
                            goto ENDTHREAD;
                     }
//                    debug(0, 0) ("S_PRIORITY: RecvCmdFromClient %x %x<<\n",ncmd,data);
                     l = data;
                     if(ncmd == 2 && l > 0)
                     {   char str[80];
                         int len;
                         rc = SQUID_pipe[threadNum].RecvDataFromClient(str,&len,l);
                         if(!rc)
                         {   int uClass,delta;
                          extern  PingerTID;
                             rc = sscanf(str,"%i,%i",&uClass,&delta);
//                    debug(0, 0) ("S_PRIORITY: %s %i %i <<\n",str, uClass,delta);
                             if(uClass > 0 && uClass <= 4 && delta > -32 && delta < 32)
                             {   debug(0, 0) ("SQUID_ClientWork: Change main thread (%i) priority to %i,%i\n", SquidMainTID,uClass,delta);
                                 DosSetPriority (PRTYS_THREAD,  uClass, delta, SquidMainTID);
                                 if(PingerTID > 0)
                                 { debug(0, 0) ("SQUID_ClientWork: Change Pinger thread (%i) priority to %i,%i\n", PingerTID,uClass,delta);
                                   DosSetPriority (PRTYS_THREAD,  uClass, delta, PingerTID);
                                 }

                             }
                         }
                     }
                 }
                   break;

               case S_DEBUG:
                 {   int l;
                     rc = SQUID_pipe[threadNum].RecvCmdFromClient(&ncmd,&data);
                     if(rc)
                     {  if(rc == -1)
                         {  rc = SQUID_pipe[threadNum].QueryState();
                            if(rc == ERROR_BAD_PIPE || rc == ERROR_PIPE_NOT_CONNECTED)
                                 break; // клиент подох ??
                         }
                         debug(0, 0) ("WARNING: SQUID_ClientWork: RecvCmdFromClient error %x %s\n",rc,xstdio_strerror());
                            goto ENDTHREAD;
                     }
                     l = data;
                     if(ncmd == 2 && l > 0)
                     {   char str[80];
                         int len;
                         rc = SQUID_pipe[threadNum].RecvDataFromClient(str,&len,l);
                         if(!rc)
                         {   int level, section;
                             rc = sscanf(str,"%i,%i",&section,&level);
                             if(section >= 0 && section <MAX_DEBUG_SECTIONS)
                                       debugLevels[section] = level;
                         }
                     }

                 }
                  break;
               case S_KILL:
           debug(1, 1) ("Preparing for killing after %d requests\n",
               statCounter.client_http.requests);
               do_shutdown++;
           SquidShutdown(NULL);
                  break;
             }
            ncmd = 0;
           break;
         default:
            ncmd = 0;
           break;

      } //endof switch(ncmd)

   } while(ncmd);
/*****************/

ENDTHREAD:
    LSthreads.state[threadNum]=0;
    debug(0, 2) ("SQUID_ClientWork: Pipe Closing %s %x %x\n",PipeName, threadNum ,SQUID_pipe[threadNum].Hpipe);
//     DosSleep(3000);
//     rc = DosDisConnectNPipe(SQUID_pipe[threadNum].Hpipe);
//     rc += DosClose(SQUID_pipe[threadNum].Hpipe);
    rc = SQUID_pipe[threadNum].Close();
    debug(0, 2) ("SQUID_ClientWork: Pipe Close %s rc=%x\n",PipeName,rc);
    fflush(stdout);
   while(__lxchg(&LSthreads.semaphore, LOCKED))
                                       DosSleep(1);

//   sgLogError("End thread %i\n",threadNum);
   LSthreads.num--;
   LSthreads.thread_id[threadNum] = -1;
   if(LSthreads.thread_id[LSthreads.next_free] != -1 || LSthreads.next_free > threadNum)
                                                               LSthreads.next_free = threadNum;
   LSthreads.Nclients--;     // число живых клиентов
   __lxchg(&LSthreads.semaphore, UNLOCKED);

    DosSleep(100);

}


int startServerThreads(void)
{  int i,ii, id, idd;
//   id = _beginthread(TestTest,NULL, STACK_SIZE*16,NULL);
//DosSleep(1000);
//DosSleep(1000);
// return;
   for(i=0;i<MAX_NUM_THREADS;i++)
   { LSthreads.thread_id[i] = -1;
   }
   LSthreads.next_free = 0;
M0:
   LSthreads.working = 0; // нужно для организации задержки ожидания запуска первого клиента

   idd = LSthreads.next_free;
   ThreadStart = 1;
   debug(50, 0) ("startServerThreads:_beginthread\n");
   id = _beginthread(SQUID_ClientWork,NULL, STACK_SIZE,(void *) &idd);
   debug(50, 0) ("startServerThreads:_beginthread id=%i\n",id );
   do
   { DosSleep(1);
   } while(ThreadStart == 1);

   while(__lxchg(&LSthreads.semaphore, LOCKED)) DosSleep(1);
   LSthreads.num++;
   LSthreads.thread_id[LSthreads.next_free] = id;
   for(i = 0; i < MAX_NUM_THREADS; i++)
      {  ii = (i + LSthreads.next_free) % MAX_NUM_THREADS;
         if(LSthreads.thread_id[ii] == -1)
         {     LSthreads.next_free = ii;
               break;
         }
      }
   ThreadStart = 3;

   __lxchg(&LSthreads.semaphore, UNLOCKED);

   return 0;
}

int SquidKillAllChilds(void)
{
    if(squid_fd_table.NumChilds)
    {  int i,rc;
       for(i=squid_fd_table.NumChilds-1;i>=0;i--)
       {  rc = DosKillProcess(0, squid_fd_table.listChilds[i].pid);
         if (rc != NO_ERROR)
          {     debug(50, 0) ("DosKillProcess rc =%i\n",rc );
          }
          DosSleep(1);
       }
       squid_fd_table.NumChilds = 0;
    }

    DosSleep(100);
}

/* следим за наличием внешних задач */
void _Optlink SQUID_WatchDog(void *param)
{   int i,rc, razproblem=0,isproblem, isrebuild=0;
    PID pidChild,pidTerminate;
    RESULTCODES ChildRC  = {0};       /* Results from child process  */

    _control87(EM_UNDERFLOW,EM_UNDERFLOW);

    for(;;)
    {  DosSleep(1000);
       getCurrentTime();
       DosSleep(1000);
       getCurrentTime();
       if (do_reconfigure) continue;
       if (do_rotate)      continue;
       if (do_shutdown)    continue;
       if(store_dirs_rebuilding)
       {   if(opt_debug_stderr <= 5 && Config.onoff.UseANSI_stdout)
           {  fprintf(stderr, "\r" WARNING_COLOR "Store Dirs Rebuilding %i " NORMAL_COLOR "\r", store_dirs_rebuild_progress);
              fflush(stderr);
           }
           isrebuild = 1;
       } else {
           if(isrebuild)
           {   fprintf(stderr, "\n");   fflush(stderr); }
           isrebuild = 0;
       }
//
//printf("%i %i %i %i  \r",statCounter.select_loops,statCounter.select_loops2[0],
//                         statCounter.select_loops2[1],statCounter.select_loops2[2]);
//fflush(stdout);
      if(squid_fd_table.NumChilds)
      {  isproblem = 0;
         for(i=0;i < squid_fd_table.NumChilds;i++)
         {
            pidChild = squid_fd_table.listChilds[i].pid;
      rc = DosWaitChild(DCWA_PROCESS,    /* Look at only the process specified */
                      DCWW_NOWAIT,     /* NoWait until a child terminates      */
                      &ChildRC,        /* Termination codes returned         */
                      &pidTerminate,       /* pid of terminating process         */
                      pidChild);   /* Process (pid) to look at  */
           if (rc == NO_ERROR) continue;
           if (rc == ERROR_CHILD_NOT_COMPLETE) continue;

           if(rc == ERROR_WAIT_NO_CHILDREN || rc == ERROR_NO_CHILD_PROCESS || rc == ERROR_INVALID_PROCID)
           {
              debug(1, 0) ("WARNING:SQUID_WatchDog:proccess[%i] (%d,%s) DosWaitChild rc =%d %s\n",
                                   i,pidChild,squid_fd_table.listChilds[i].pProgname,rc, GetOS2ErrorMessage(rc));
              isproblem++;

           } else if (rc != NO_ERROR) {
              debug(1, 0) ("WARNING:SQUID_WatchDog:DosWaitChild child[%i] pid=%d rc =%d %s\n",
                           i,pidChild, rc, GetOS2ErrorMessage(rc));
           }
         }
         if(isproblem) razproblem++;
         else          razproblem = 0;
         if(razproblem > 8)
         {    debug(1, 0) ("WARNING:SQUID_WatchDog: %d times we have problems=> Shutdown\n",razproblem);
                    goto ENDTHR;
         }

      }

    }
ENDTHR:
    do_shutdown++;
    SquidShutdown(NULL);
    DosSleep(10);
}

#endif
// _SQUID_OS2VAC_
