示例#1
0
int component_control_main() {
    int error;

    if (pre_init) {
        pre_init();
    }

    /* we call pre_init_interface_sync in all circumstances, even if we do not support
     * init, as the implementation already has an internal guard for init support and
     * so the function will just do nothing without init support. Always calling it
     * provides a bit more flexibility in the future, and is consistent with the
     * post_init version which *does* do something even if we do not support init
     */
    error = pre_init_interface_sync();
    if (error) {
        return error;
    }

    if (post_init) {
        post_init();
    }

    error = post_init_interface_sync();
    if (error) {
        return error;
    }

    /*- if me.type.control -*/
        return run();
    /*- else -*/
        return 0;
    /*- endif -*/
}
示例#2
0
file::file (uint8_t *_b, uint32_t b_n) {
    pre_init ();
    this->_b = _b;
    this->b_n = b_n;
    this->free_ = false;
    _ = true;
}
示例#3
0
文件: R.cpp 项目: Marneus68/rog
 void Rgame::Run(void)
 {
     pre_init();
     init();
     main_loop();
     cleanup();
     
     return;
 }
示例#4
0
/*
 * Main method.
 */
int main(int argc, char *argv[]) {
	int rc;

	pre_init();

	rc = pre_handler(argc, argv);

	quit(0);

	// never reached.
	return 0;
}
示例#5
0
/////////////////////////////////////////////////////////
//
// gemsdlwindow
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
gemsdlwindow :: gemsdlwindow(void) :
  m_surface(NULL),
  m_videoFlags(0),
  m_bpp(0)
{
  if(!sdl_count) {
    pre_init();
    if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )
      throw(GemException("could not initialize SDL window infrastructure"));
    SDL_EnableUNICODE(1);
  }
  sdl_count++;
}
int main()
{
	int selected_option = NONE_OPTION;
	pre_init();

	do
	{
		print_menu();
		selected_option = get_opt();
		perform_effect(selected_option);
	}
	while(selected_option != EXIT_OPTION);

	return 0;
}
示例#7
0
int32_t        dnand_fs_read(
                uint32_t            cid,
                uint32_t            offset,
                uint8_t             *pbuf,
                uint32_t            size )
{
    int32_t      rtn;
    uint16_t     blk;

    if( pbuf == NULL )
    {
        return(DNAND_PARAM_ERROR);
    }

    if( cid >= DNAND_ID_ENUM_MAX )
    {
        return(DNAND_PARAM_ERROR);
    }
    if( cid >= DNAND_FS_CLID_NUM )
    {
        return(DNAND_PARAM_ERROR);
    }

    memset( pbuf, 0x00, size );

    rtn    = pre_init();
    if( rtn != DNAND_NO_ERROR )
    {
        return(rtn);
    }

    blk    = get_clid( cid );
    if( blk < DNAND_FS_BLK_DATA_ST )
    {
        return(DNAND_MNG_ERROR);
    }
    if( blk >= DNAND_FS_BLK_NUM )
    {
        return(DNAND_NOEXISTS_ERROR);
    }
    rtn    = inter_fs_read( blk, offset, pbuf, size );

    return(rtn);
}
示例#8
0
int main( int argc, char *argv[] )
{
    N = 10000;

    if( argc > 1 )
        N = atoi(argv[1]);

    setbuf(stdout, NULL);


	//Memoization 
	pre_init();

    calculate();

    epilog();

    return 0;
}
示例#9
0
int32_t        dnand_fs_write(
                uint32_t            cid,
                uint32_t            offset,
                uint8_t             *pbuf,
                uint32_t            size )
{
    int32_t      rtn;
    uint16_t     blk;

    if( pbuf == NULL )
    {
        return(DNAND_PARAM_ERROR);
    }
    if( cid >= DNAND_ID_ENUM_MAX )
    {
        return(DNAND_PARAM_ERROR);
    }
    if( cid >= DNAND_FS_CLID_NUM )
    {
        return(DNAND_PARAM_ERROR);
    }

    rtn    = pre_init();
    if( rtn != DNAND_NO_ERROR )
    {
        return(rtn);
    }

    blk    = get_clid( cid );
    rtn    = inter_fs_write( cid, blk, offset, pbuf, size );
    if( rtn == DNAND_NO_ERROR )
    {
        rtn    = update_memng( cid );
    }
    return(rtn);
}
示例#10
0
NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
{
    const char *myname = "multi_server_main";
    VSTREAM *stream = 0;
    char   *root_dir = 0;
    char   *user_name = 0;
    int     debug_me = 0;
    int     daemon_mode = 1;
    char   *service_name = basename(argv[0]);
    int     delay;
    int     c;
    int     fd;
    va_list ap;
    MAIL_SERVER_INIT_FN pre_init = 0;
    MAIL_SERVER_INIT_FN post_init = 0;
    MAIL_SERVER_LOOP_FN loop = 0;
    int     key;
    char   *transport = 0;

#if 0
    char   *lock_path;
    VSTRING *why;

#endif
    int     alone = 0;
    int     zerolimit = 0;
    WATCHDOG *watchdog;
    char   *oname_val;
    char   *oname;
    char   *oval;
    const char *err;
    char   *generation;
    int     msg_vstream_needed = 0;
    int     redo_syslog_init = 0;

    /*
     * Process environment options as early as we can.
     */
    if (getenv(CONF_ENV_VERB))
	msg_verbose = 1;
    if (getenv(CONF_ENV_DEBUG))
	debug_me = 1;

    /*
     * Don't die when a process goes away unexpectedly.
     */
    signal(SIGPIPE, SIG_IGN);

    /*
     * Don't die for frivolous reasons.
     */
#ifdef SIGXFSZ
    signal(SIGXFSZ, SIG_IGN);
#endif

    /*
     * May need this every now and then.
     */
    var_procname = mystrdup(basename(argv[0]));
    set_mail_conf_str(VAR_PROCNAME, var_procname);

    /*
     * Initialize logging and exit handler. Do the syslog first, so that its
     * initialization completes before we enter the optional chroot jail.
     */
    msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
    if (msg_verbose)
	msg_info("daemon started");

    /*
     * Check the Postfix library version as soon as we enable logging.
     */
    MAIL_VERSION_CHECK;

    /*
     * Initialize from the configuration file. Allow command-line options to
     * override compiled-in defaults or configured parameter values.
     */
    mail_conf_suck();

    /*
     * Register dictionaries that use higher-level interfaces and protocols.
     */
    mail_dict_init();
 
    /*
     * After database open error, continue execution with reduced
     * functionality.
     */
    dict_allow_surrogate = 1;

    /*
     * Pick up policy settings from master process. Shut up error messages to
     * stderr, because no-one is going to see them.
     */
    opterr = 0;
    while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
	switch (c) {
	case 'c':
	    root_dir = "setme";
	    break;
	case 'd':
	    daemon_mode = 0;
	    break;
	case 'D':
	    debug_me = 1;
	    break;
	case 'i':
	    mail_conf_update(VAR_MAX_IDLE, optarg);
	    break;
	case 'l':
	    alone = 1;
	    break;
	case 'm':
	    mail_conf_update(VAR_MAX_USE, optarg);
	    break;
	case 'n':
	    service_name = optarg;
	    break;
	case 'o':
	    oname_val = mystrdup(optarg);
	    if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
		msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
	    mail_conf_update(oname, oval);
	    if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
		redo_syslog_init = 1;
	    myfree(oname_val);
	    break;
	case 's':
	    if ((socket_count = atoi(optarg)) <= 0)
		msg_fatal("invalid socket_count: %s", optarg);
	    break;
	case 'S':
	    stream = VSTREAM_IN;
	    break;
	case 'u':
	    user_name = "setme";
	    break;
	case 't':
	    transport = optarg;
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case 'V':
	    if (++msg_vstream_needed == 1)
		msg_vstream_init(mail_task(var_procname), VSTREAM_ERR);
	    break;
	case 'z':
	    zerolimit = 1;
	    break;
	default:
	    msg_fatal("invalid option: %c", c);
	    break;
	}
    }

    /*
     * Initialize generic parameters.
     */
    mail_params_init();
    if (redo_syslog_init)
	msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);

    /*
     * If not connected to stdin, stdin must not be a terminal.
     */
    if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
	msg_vstream_init(var_procname, VSTREAM_ERR);
	msg_fatal("do not run this command by hand");
    }

    /*
     * Application-specific initialization.
     */
    va_start(ap, service);
    while ((key = va_arg(ap, int)) != 0) {
	switch (key) {
	case MAIL_SERVER_INT_TABLE:
	    get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
	    break;
	case MAIL_SERVER_LONG_TABLE:
	    get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *));
	    break;
	case MAIL_SERVER_STR_TABLE:
	    get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
	    break;
	case MAIL_SERVER_BOOL_TABLE:
	    get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
	    break;
	case MAIL_SERVER_TIME_TABLE:
	    get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
	    break;
	case MAIL_SERVER_RAW_TABLE:
	    get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
	    break;
	case MAIL_SERVER_NINT_TABLE:
	    get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *));
	    break;
	case MAIL_SERVER_NBOOL_TABLE:
	    get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *));
	    break;
	case MAIL_SERVER_PRE_INIT:
	    pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_POST_INIT:
	    post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_LOOP:
	    loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
	    break;
	case MAIL_SERVER_EXIT:
	    multi_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
	    break;
	case MAIL_SERVER_PRE_ACCEPT:
	    multi_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
	    break;
	case MAIL_SERVER_PRE_DISCONN:
	    multi_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
	    break;
	case MAIL_SERVER_IN_FLOW_DELAY:
	    multi_server_in_flow_delay = 1;
	    break;
	case MAIL_SERVER_SOLITARY:
	    if (stream == 0 && !alone)
		msg_fatal("service %s requires a process limit of 1",
			  service_name);
	    break;
	case MAIL_SERVER_UNLIMITED:
	    if (stream == 0 && !zerolimit)
		msg_fatal("service %s requires a process limit of 0",
			  service_name);
	    break;
	case MAIL_SERVER_PRIVILEGED:
	    if (user_name)
		msg_fatal("service %s requires privileged operation",
			  service_name);
	    break;
	default:
	    msg_panic("%s: unknown argument type: %d", myname, key);
	}
    }
    va_end(ap);

    if (root_dir)
	root_dir = var_queue_dir;
    if (user_name)
	user_name = var_mail_owner;

    /*
     * Can options be required?
     */
    if (stream == 0) {
	if (transport == 0)
	    msg_fatal("no transport type specified");
	if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
	    multi_server_accept = multi_server_accept_inet;
	else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
	    multi_server_accept = multi_server_accept_local;
#ifdef MASTER_XPORT_NAME_PASS
	else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
	    multi_server_accept = multi_server_accept_pass;
#endif
	else
	    msg_fatal("unsupported transport type: %s", transport);
    }

    /*
     * Retrieve process generation from environment.
     */
    if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
	if (!alldig(generation))
	    msg_fatal("bad generation: %s", generation);
	OCTAL_TO_UNSIGNED(multi_server_generation, generation);
	if (msg_verbose)
	    msg_info("process generation: %s (%o)",
		     generation, multi_server_generation);
    }

    /*
     * Optionally start the debugger on ourself.
     */
    if (debug_me)
	debug_process();

    /*
     * Traditionally, BSD select() can't handle multiple processes selecting
     * on the same socket, and wakes up every process in select(). See TCP/IP
     * Illustrated volume 2 page 532. We avoid select() collisions with an
     * external lock file.
     */

    /*
     * XXX Can't compete for exclusive access to the listen socket because we
     * also have to monitor existing client connections for service requests.
     */
#if 0
    if (stream == 0 && !alone) {
	lock_path = concatenate(DEF_PID_DIR, "/", transport,
				".", service_name, (char *) 0);
	why = vstring_alloc(1);
	if ((multi_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
				      (struct stat *) 0, -1, -1, why)) == 0)
	    msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
	close_on_exec(vstream_fileno(multi_server_lock), CLOSE_ON_EXEC);
	myfree(lock_path);
	vstring_free(why);
    }
#endif

    /*
     * Set up call-back info.
     */
    multi_server_service = service;
    multi_server_name = service_name;
    multi_server_argv = argv + optind;

    /*
     * Run pre-jail initialization.
     */
    if (chdir(var_queue_dir) < 0)
	msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
    if (pre_init)
	pre_init(multi_server_name, multi_server_argv);

    /*
     * Optionally, restrict the damage that this process can do.
     */
    resolve_local_init();
    tzset();
    chroot_uid(root_dir, user_name);

    /*
     * Run post-jail initialization.
     */
    if (post_init)
	post_init(multi_server_name, multi_server_argv);

    /*
     * Are we running as a one-shot server with the client connection on
     * standard input? If so, make sure the output is written to stdout so as
     * to satisfy common expectation.
     */
    if (stream != 0) {
	vstream_control(stream,
			VSTREAM_CTL_DOUBLE,
			VSTREAM_CTL_WRITE_FD, STDOUT_FILENO,
			VSTREAM_CTL_END);
	service(stream, multi_server_name, multi_server_argv);
	vstream_fflush(stream);
	multi_server_exit();
    }

    /*
     * Running as a semi-resident server. Service connection requests.
     * Terminate when we have serviced a sufficient number of clients, when
     * no-one has been talking to us for a configurable amount of time, or
     * when the master process terminated abnormally.
     */
    if (var_idle_limit > 0)
	event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit);
    for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
	event_enable_read(fd, multi_server_accept, CAST_INT_TO_CHAR_PTR(fd));
	close_on_exec(fd, CLOSE_ON_EXEC);
    }
    event_enable_read(MASTER_STATUS_FD, multi_server_abort, (char *) 0);
    close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
    watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0);

    /*
     * The event loop, at last.
     */
    while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
	if (multi_server_lock != 0) {
	    watchdog_stop(watchdog);
	    if (myflock(vstream_fileno(multi_server_lock), INTERNAL_LOCK,
			MYFLOCK_OP_EXCLUSIVE) < 0)
		msg_fatal("select lock: %m");
	}
	watchdog_start(watchdog);
	delay = loop ? loop(multi_server_name, multi_server_argv) : -1;
	event_loop(delay);
    }
    multi_server_exit();
}
示例#11
0
int SPECTACLE_BASE :: init(double p[], int n_args)
{
   float outskip = p[0];
   float inskip = p[1];
   inputdur = p[2];
   amp = p[3];
   ringdur = p[4];
   fft_len = (int) p[5];
   window_len = (int) p[6];
   window_type = getWindowType(p[7]);
   float overlap = p[8];

   /* Make sure FFT length is a power of 2 <= MAXFFTLEN and <= RTBUFSAMPS. */
   bool valid = false;
   for (int x = 1; x <= MAXFFTLEN; x *= 2) {
      if (fft_len == x) {
         valid = true;
         break;
      }
   }
   if (!valid || fft_len > MAXFFTLEN)
      return die(instname(), "FFT length must be a power of two <= %d",
                                                                  MAXFFTLEN);

// FIXME: now this isn't a problem; instead, decimation can't be larger
// than RTBUFSAMPS.  But must couch errmsg in terms of overlap and fft length,
// not decimation...
#if 0
   if (fft_len > RTBUFSAMPS)
      return die(instname(),
                 "FFT length must be a power of two less than or equal\n"
                 "to the output buffer size set in rtsetparams (currently %d).",
                 RTBUFSAMPS);
#endif
   half_fft_len = fft_len / 2;
   fund_anal_freq = SR / (float) fft_len;

   /* Make sure window length is a power of 2 >= FFT length. */
   valid = false;
   for (int x = fft_len; x <= MAXWINDOWLEN; x *= 2) {
      if (window_len == x) {
         valid = true;
         break;
      }
   }
   if (!valid)
      return die(instname(),
                     "Window length must be a power of two >= FFT length\n"
                     "(currently %d) and <= %d.", fft_len, MAXWINDOWLEN);

   /* Make sure overlap is a power of 2 in our safety range. */
   valid = false;
//FIXME: need to adjust MINOVERLAP so that iterations is never 0 in run()
// This might depend upon window_len??
   for (float x = MINOVERLAP; x <= MAXOVERLAP; x *= 2.0) {
      if (overlap == x) {
         valid = true;
         break;
      }
   }
   if (!valid)
      return die(instname(),
                 "Overlap must be a power of two between %g and %g.",
                 MINOVERLAP, MAXOVERLAP);
   int_overlap = (int) overlap;

   /* derive decimation from overlap */
   decimation = (int) (fft_len / overlap);

   DPRINT2("fft_len=%d, decimation=%d\n", fft_len, decimation);

   if (pre_init(p, n_args) != 0)    /* can modify ringdur */
      return DONT_SCHEDULE;

   iamparray = floc(1);
   if (iamparray) {
      int lenamp = fsize(1);
      tableset(SR, inputdur, lenamp, iamptabs);
   }
   else
      rtcmix_advise(instname(), "Setting input amplitude curve to all 1's.");

   oamparray = floc(2);
   if (oamparray) {
      int lenamp = fsize(2);
      tableset(SR, inputdur + ringdur, lenamp, oamptabs);
   }
   else
      rtcmix_advise(instname(), "Setting output amplitude curve to all 1's.");

   if (rtsetinput(inskip, this) == -1)
      return DONT_SCHEDULE;
   if (inchan >= inputChannels())
      return die(instname(), "You asked for channel %d of a %d-channel file.",
                                                   inchan, inputChannels());

   /* <latency> is the delay before the FFT looks at actual input rather than
      zero-padding.  Need to let inst run long enough to compensate for this.
   */
   window_len_minus_decimation = window_len - decimation;
   latency = window_len + window_len_minus_decimation;
   float latency_dur = latency * (1.0 / SR);
   if (rtsetoutput(outskip, latency_dur + inputdur + ringdur, this) == -1)
      return DONT_SCHEDULE;
   total_insamps = (int)(inputdur * SR);    /* without latency_dur */
   input_end_frame = total_insamps + latency;
   DPRINT1("input_end_frame=%d\n", input_end_frame);

   input = new float [window_len];           /* input buffer */
   output = new float [window_len];          /* output buffer */
   anal_window = new float [window_len];     /* analysis window */
   synth_window = new float [window_len];    /* synthesis window */
   fft_buf = new float [fft_len];            /* FFT buffer */
   anal_chans = new float [fft_len + 2];     /* analysis channels */

   if (make_windows() != 0)
      return DONT_SCHEDULE;

   /* Delay dry output by window_len - decimation to sync with wet sig. */
   drybuf = new float [decimation];
   dry_delay = new DLineN(window_len);
   dry_delay->setDelay((float) window_len_minus_decimation);

   /* Init iamp and oamp to starting amplitudes. */
   iamp = (iamparray == NULL) ? 1.0 : iamparray[0];
   oamp = (oamparray == NULL) ? amp : oamparray[0];

   skip = (int) (SR / (float) resetval);

   if (post_init(p, n_args) != 0)
      return DONT_SCHEDULE;

   return nSamps();
}
示例#12
0
int main(int argc, char *argv[])
{

  fprintf(stderr,"Start init\n"); fflush(stderr);

  /* perform initializations */
  pre_init(argc, argv);
  // all log files are now defined

  if (RESTARTMODE == 1) {
    if (restart_init(WHICHFILE) >= 1) {
      dualfprintf(fail_file, "main:restart_init: failure\n");
    }
  } else if (init() >= 1) {
    dualfprintf(fail_file, "main:init: failure\n");
  }

  post_init();			// initialize general parameters

  trifprintf("proc: %04d : End init\n", myid);


  /* Do initial diagnostics */
  if (DODIAGS) {
    trifprintf("proc: %04d : Start initial diagnostics\n", myid);
    // no error_check since if init passed, diag(0) should pass
    diag(0);
    trifprintf("proc: %04d : End initial diagnostics\n", myid);
  }

  trifprintf("proc: %04d : Start computation\n", myid);

  while (t < tf) {


    /* step variables forward in time */
    nstroke = 0;
    step_ch();

    // must check before MPI operation (since asymmetries would
    // desynchronize cpus)
    if (error_check()) {
      fprintf(fail_file, "error_check detected failure at main:2\n");
      fflush(fail_file);
    }
    //^^ otherwise ok
    
    // eventually all cpus come here, either in failure mode or not,
    // and cleanly tell others if failed/exit/dump/etc.

    postdt(); // here one can alter variables and try to restart, or implement any post step operations

    /* perform diagnostics */
    // no error check since assume if step_ch passed, diag(1) will pass
    if (DODIAGS)
      diag(1);

    /* restart dump */
    // if(nstep == 130) restart_write(1) ;

    nstep++;
    // restartsteps[whichrestart]=realnstep;


    trifprintf("%21.15g %21.15g %10.5g %8ld %8ld %8d\n", t, dt,
	      cour, nstep, realnstep, nstroke);
  }
  trifprintf("proc: %04d : End computation\n", myid);

  /* do final diagnostics */
  if (DODIAGS)
    diag(2);


  trifprintf("ns,ts: %ld %ld\n", nstep, nstep *(long)( totalsize[1] * totalsize[2]));

  myexit(0);
  return (0);
}
示例#13
0
NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,...)
{
    char   *myname = "trigger_server_main";
    char   *root_dir = 0;
    char   *user_name = 0;
    int     debug_me = 0;
    char   *service_name = basename(argv[0]);
    VSTREAM *stream = 0;
    int     delay;
    int     c;
    int     socket_count = 1;
    int     fd;
    va_list ap;
    MAIL_SERVER_INIT_FN pre_init = 0;
    MAIL_SERVER_INIT_FN post_init = 0;
    MAIL_SERVER_LOOP_FN loop = 0;
    int     key;
    char    buf[TRIGGER_BUF_SIZE];
    int     len;
    char   *transport = 0;
    char   *lock_path;
    VSTRING *why;
    int     alone = 0;
    int     zerolimit = 0;
    WATCHDOG *watchdog;
    char   *oval;

    /*
     * Process environment options as early as we can.
     */
    if (getenv(CONF_ENV_VERB))
	msg_verbose = 1;
    if (getenv(CONF_ENV_DEBUG))
	debug_me = 1;

    /*
     * Don't die when a process goes away unexpectedly.
     */
    signal(SIGPIPE, SIG_IGN);

    /*
     * Don't die for frivolous reasons.
     */
#ifdef SIGXFSZ
    signal(SIGXFSZ, SIG_IGN);
#endif

    /*
     * May need this every now and then.
     */
    var_procname = mystrdup(basename(argv[0]));
    set_mail_conf_str(VAR_PROCNAME, var_procname);

    /*
     * Initialize logging and exit handler. Do the syslog first, so that its
     * initialization completes before we enter the optional chroot jail.
     */
    msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY);
    if (msg_verbose)
	msg_info("daemon started");

    /*
     * Initialize from the configuration file. Allow command-line options to
     * override compiled-in defaults or configured parameter values.
     */
    mail_conf_suck();

    /*
     * Register dictionaries that use higher-level interfaces and protocols.
     */
    mail_dict_init();

    /*
     * Pick up policy settings from master process. Shut up error messages to
     * stderr, because no-one is going to see them.
     */
    opterr = 0;
    while ((c = GETOPT(argc, argv, "cDi:lm:n:o:s:St:uvzZ")) > 0) {
	switch (c) {
	case 'c':
	    root_dir = "setme";
	    break;
	case 'D':
	    debug_me = 1;
	    break;
	case 'i':
	    mail_conf_update(VAR_MAX_IDLE, optarg);
	    break;
	case 'l':
	    alone = 1;
	    break;
	case 'm':
	    mail_conf_update(VAR_MAX_USE, optarg);
	    break;
	case 'n':
	    service_name = optarg;
	    break;
	case 'o':
	    if ((oval = split_at(optarg, '=')) == 0)
		oval = "";
	    mail_conf_update(optarg, oval);
	    break;
	case 's':
	    if ((socket_count = atoi(optarg)) <= 0)
		msg_fatal("invalid socket_count: %s", optarg);
	    break;
	case 'S':
	    stream = VSTREAM_IN;
	    break;
	case 't':
	    transport = optarg;
	    break;
	case 'u':
	    user_name = "setme";
	    break;
	case 'v':
	    msg_verbose++;
	    break;
	case 'z':
	    zerolimit = 1;
	    break;
	case 'Z':
	    msg_debug++;
	    break;
	default:
	    msg_fatal("invalid option: %c", c);
	    break;
	}
    }

    /*
     * Initialize generic parameters.
     */
    mail_params_init();

    /*
     * Application-specific initialization.
     */
    va_start(ap, service);
    while ((key = va_arg(ap, int)) != 0) {
	switch (key) {
	case MAIL_SERVER_INT_TABLE:
	    get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *));
	    break;
	case MAIL_SERVER_STR_TABLE:
	    get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *));
	    break;
	case MAIL_SERVER_BOOL_TABLE:
	    get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *));
	    break;
	case MAIL_SERVER_TIME_TABLE:
	    get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *));
	    break;
	case MAIL_SERVER_RAW_TABLE:
	    get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *));
	    break;
	case MAIL_SERVER_PRE_INIT:
	    pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_POST_INIT:
	    post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
	    break;
	case MAIL_SERVER_LOOP:
	    loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
	    break;
	case MAIL_SERVER_EXIT:
	    trigger_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
	    break;
	case MAIL_SERVER_PRE_ACCEPT:
	    trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
	    break;
	case MAIL_SERVER_IN_FLOW_DELAY:
	    trigger_server_in_flow_delay = 1;
	    break;
	case MAIL_SERVER_SOLITARY:
	    if (!alone)
		msg_fatal("service %s requires a process limit of 1",
			  service_name);
	    break;
	case MAIL_SERVER_UNLIMITED:
	    if (!zerolimit)
		msg_fatal("service %s requires a process limit of 0",
			  service_name);
	    break;
	default:
	    msg_panic("%s: unknown argument type: %d", myname, key);
	}
    }
    va_end(ap);

    if (root_dir)
	root_dir = var_queue_dir;
    if (user_name)
	user_name = var_mail_owner;

    /*
     * If not connected to stdin, stdin must not be a terminal.
     */
    if (stream == 0 && isatty(STDIN_FILENO)) {
	msg_vstream_init(var_procname, VSTREAM_ERR);
	msg_fatal("do not run this command by hand");
    }

    /*
     * Can options be required?
     * 
     * XXX Initially this code was implemented with UNIX-domain sockets, but
     * Solaris <= 2.5 UNIX-domain sockets misbehave hopelessly when the
     * client disconnects before the server has accepted the connection.
     * Symptom: the server accept() fails with EPIPE or EPROTO, but the
     * socket stays readable, so that the program goes into a wasteful loop.
     * 
     * The initial fix was to use FIFOs, but those turn out to have their own
     * problems, witness the workarounds in the fifo_listen() routine.
     * Therefore we support both FIFOs and UNIX-domain sockets, so that the
     * user can choose whatever works best.
     * 
     * Well, I give up. Solaris UNIX-domain sockets still don't work properly,
     * so it will have to limp along with a streams-specific alternative.
     */
    if (stream == 0) {
	if (transport == 0)
	    msg_fatal("no transport type specified");
	if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
	    trigger_server_accept = trigger_server_accept_local;
	else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0)
	    trigger_server_accept = trigger_server_accept_fifo;
	else
	    msg_fatal("unsupported transport type: %s", transport);
    }

    /*
     * Optionally start the debugger on ourself.
     */
    if (debug_me)
	debug_process();

    /*
     * Traditionally, BSD select() can't handle multiple processes selecting
     * on the same socket, and wakes up every process in select(). See TCP/IP
     * Illustrated volume 2 page 532. We avoid select() collisions with an
     * external lock file.
     */
    if (stream == 0 && !alone) {
	lock_path = concatenate(DEF_PID_DIR, "/", transport,
				".", service_name, (char *) 0);
	why = vstring_alloc(1);
	if ((trigger_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
				      (struct stat *) 0, -1, -1, why)) == 0)
	    msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
	close_on_exec(vstream_fileno(trigger_server_lock), CLOSE_ON_EXEC);
	myfree(lock_path);
	vstring_free(why);
    }

    /*
     * Set up call-back info.
     */
    trigger_server_service = service;
    trigger_server_name = service_name;
    trigger_server_argv = argv + optind;

    /*
     * Run pre-jail initialization.
     */
    if (chdir(var_queue_dir) < 0)
	msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
    if (pre_init)
	pre_init(trigger_server_name, trigger_server_argv);

    /*
     * Optionally, restrict the damage that this process can do.
     */
    resolve_local_init();
    chroot_uid(root_dir, user_name);

    /*
     * Run post-jail initialization.
     */
    if (post_init)
	post_init(trigger_server_name, trigger_server_argv);

    /*
     * Are we running as a one-shot server with the client connection on
     * standard input?
     */
    if (stream != 0) {
	if ((len = read(vstream_fileno(stream), buf, sizeof(buf))) <= 0)
	    msg_fatal("read: %m");
	service(buf, len, trigger_server_name, trigger_server_argv);
	vstream_fflush(stream);
	trigger_server_exit();
    }

    /*
     * Running as a semi-resident server. Service connection requests.
     * Terminate when we have serviced a sufficient number of clients, when
     * no-one has been talking to us for a configurable amount of time, or
     * when the master process terminated abnormally.
     */
    if (var_idle_limit > 0)
	event_request_timer(trigger_server_timeout, (char *) 0, var_idle_limit);
    for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
	event_enable_read(fd, trigger_server_accept, CAST_INT_TO_CHAR_PTR(fd));
	close_on_exec(fd, CLOSE_ON_EXEC);
    }
    event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0);
    close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC);
    close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC);
    watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0);

    /*
     * The event loop, at last.
     */
    while (var_use_limit == 0 || use_count < var_use_limit) {
	if (trigger_server_lock != 0) {
	    watchdog_stop(watchdog);
	    if (myflock(vstream_fileno(trigger_server_lock), INTERNAL_LOCK,
			MYFLOCK_OP_EXCLUSIVE) < 0)
		msg_fatal("select lock: %m");
	}
	watchdog_start(watchdog);
	delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1;
	event_loop(delay);
    }
    trigger_server_exit();
}