当前位置:文档之家› apache的启动过程原代码分析

apache的启动过程原代码分析

apache的启动过程原代码分析
apache的启动过程原代码分析

1./include/ 这个文件里面申明了基本的内容,如文件路径,字符串长度,等等。

2./server/

对于apache的httpd,有很多的技术,有MPM多任务并发处理(采用记分板),内存池,线程池。。。

1.在main()有一个for(;;)里面调用了ap_mpm_run。但这个循环里好象只执行了一次,而不是一直在循环。

2.在ap_mpm_run()里,有一个while (!restart_pending && !shutdown_pending)。这个循环每一秒就往返一次,一直执行,直到进程结束。如果是第一次启动,在这个循环里,会调用一个startup_children();在这里面又有一个循环调用make_child()产生初始数量的子进程。

3.在上面的while里,perform_idle_server_maintenance(pconf)会每1秒执行一次,如果你kill -9一个子进程,这个函数就起作用,再重新调用make_child()生成一个子进程。

4.如果执行httpd –k stop,那么ap_mpm_run()会返回错误,在main()就会跳出for(;;),进程退出。5.在make_child()里,有一个fork()调用产生子进程,然后在子进程里调用child_main()进行子进程的初始化处理。

linux-lncx:/home/apache/ # ls

linux-lncx:/home/apache/ #

int main(int argc, const char * const argv[])

{

char c;

int configtestonly = 0;

const char *confname = SERVER_CONFIG_FILE;

const char *def_server_root = HTTPD_ROOT;

const char *temp_error_log = NULL;

const char *error;

process_rec *process;

server_rec *server_conf;

apr_pool_t *pglobal;

apr_pool_t *pconf;

apr_pool_t *plog; /* Pool of log streams, reset _after_ each read of conf */

apr_pool_t *ptemp; /* Pool for temporary config stuff, reset often */

apr_pool_t *pcommands; /* Pool for -D, -C and -c switches */

apr_getopt_t *opt;

apr_status_t rv;

module **mod;

const char *optarg;

APR_OPTIONAL_FN_TYPE(ap_signal_server) *signal_server;

AP_MONCONTROL(0); /* turn off profiling of startup */

process = init_process(&argc, &argv);

pglobal = process->pool;

pconf = process->pconf;

ap_server_argv0 = process->short_name;

#if APR_CHARSET_EBCDIC

if (ap_init_ebcdic(pglobal) != APR_SUCCESS) {

destroy_and_exit_process(process, 1);

}

#endif

apr_pool_create(&pcommands, pglobal);

apr_pool_tag(pcommands, "pcommands");

ap_server_pre_read_config = apr_array_make(pcommands, 1, sizeof(char *));

ap_server_post_read_config = apr_array_make(pcommands, 1, sizeof(char *));

ap_server_config_defines = apr_array_make(pcommands, 1, sizeof(char *));

error = ap_setup_prelinked_modules(process);

if (error) {

ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, 0, NULL, "%s: %s",

ap_server_argv0, error);

destroy_and_exit_process(process, 1);

}

ap_run_rewrite_args(process);

/* Maintain AP_SERVER_BASEARGS list in to allow the MPM

* to safely pass on our args from its rewrite_args() handler.

*/

apr_getopt_init(&opt, pcommands, process->argc, process->argv);

while ((rv = apr_getopt(opt, AP_SERVER_BASEARGS, &c, &optarg))

== APR_SUCCESS) {

char **new;

switch (c) {

case 'c':

new = (char **)apr_array_push(ap_server_post_read_config); *new = apr_pstrdup(pcommands, optarg);

break;

case 'C':

new = (char **)apr_array_push(ap_server_pre_read_config); *new = apr_pstrdup(pcommands, optarg);

break;

case 'd':

def_server_root = optarg;

break;

case 'D':

new = (char **)apr_array_push(ap_server_config_defines); *new = apr_pstrdup(pcommands, optarg);

/* Setting -D DUMP_VHOSTS is equivalent to setting -S */ if (strcmp(optarg, "DUMP_VHOSTS") == 0)

configtestonly = 1;

/* Setting -D DUMP_MODULES is equivalent to setting -M */ if (strcmp(optarg, "DUMP_MODULES") == 0)

configtestonly = 1;

break;

case 'e':

if (strcasecmp(optarg, "emerg") == 0) {

ap_default_loglevel = APLOG_EMERG;

}

else if (strcasecmp(optarg, "alert") == 0) {

ap_default_loglevel = APLOG_ALERT;

}

else if (strcasecmp(optarg, "crit") == 0) {

ap_default_loglevel = APLOG_CRIT;

}

else if (strncasecmp(optarg, "err", 3) == 0) {

ap_default_loglevel = APLOG_ERR;

}

else if (strncasecmp(optarg, "warn", 4) == 0) {

ap_default_loglevel = APLOG_WARNING;

}

else if (strcasecmp(optarg, "notice") == 0) {

ap_default_loglevel = APLOG_NOTICE;

}

else if (strcasecmp(optarg, "info") == 0) {

ap_default_loglevel = APLOG_INFO;

}

else if (strcasecmp(optarg, "debug") == 0) {

ap_default_loglevel = APLOG_DEBUG;

}

else {

usage(process);

}

break;

case 'E':

temp_error_log = apr_pstrdup(process->pool, optarg);

break;

case 'X':

new = (char **)apr_array_push(ap_server_config_defines);

*new = "DEBUG";

break;

case 'f':

confname = optarg;

break;

case 'v':

printf("Server version: %s\n", ap_get_server_description()); printf("Server built: %s\n", ap_get_server_built());

destroy_and_exit_process(process, 0);

case 'V':

show_compile_settings();

destroy_and_exit_process(process, 0);

case 'l':

ap_show_modules();

destroy_and_exit_process(process, 0);

case 'L':

ap_show_directives();

destroy_and_exit_process(process, 0);

case 't':

configtestonly = 1;

break;

case 'S':

configtestonly = 1;

new = (char **)apr_array_push(ap_server_config_defines);

*new = "DUMP_VHOSTS";

break;

case 'M':

configtestonly = 1;

new = (char **)apr_array_push(ap_server_config_defines);

*new = "DUMP_MODULES";

break;

case 'h':

case '?':

usage(process);

}

}

/* bad cmdline option? then we die */

if (rv != APR_EOF || opt->ind < opt->argc) {

usage(process);

}

apr_pool_create(&plog, pglobal);

apr_pool_tag(plog, "plog");

apr_pool_create(&ptemp, pconf);

apr_pool_tag(ptemp, "ptemp");

/* Note that we preflight the config file once

* before reading it _again_ in the main loop.

* This allows things, log files configuration

* for example, to settle down.

*/

ap_server_root = def_server_root;

if (temp_error_log) {

ap_replace_stderr_log(process->pool, temp_error_log);

}

/*===========下面这一段是对配置文件进行处理 ==================*/

server_conf = ap_read_config(process, ptemp, confname, &ap_conftree); if (!server_conf) {

destroy_and_exit_process(process, 1);

}

if (ap_run_pre_config(pconf, plog, ptemp) != OK) {

ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0,

NULL, "Pre-configuration failed");

destroy_and_exit_process(process, 1);

}

rv = ap_process_config_tree(server_conf, ap_conftree,

process->pconf, ptemp);

if (rv == OK) {

ap_fixup_virtual_hosts(pconf, server_conf);

ap_fini_vhost_config(pconf, server_conf);

apr_hook_sort_all();

if (configtestonly) {

ap_run_test_config(pconf, server_conf);

ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "Syntax OK"); destroy_and_exit_process(process, 0);

}

}

/*===========上面这一段是对配置文件进行处理==================*/

signal_server = APR_RETRIEVE_OPTIONAL_FN(ap_signal_server);

if (signal_server) {

int exit_status;

if (signal_server(&exit_status, pconf) != 0) {

destroy_and_exit_process(process, exit_status);

}

}

/* If our config failed, deal with that here. */

if (rv != OK) {

destroy_and_exit_process(process, 1);

}

apr_pool_clear(plog);

if ( ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) {

ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,

0, NULL, "Unable to open logs");

destroy_and_exit_process(process, 1);

}

if ( ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) {

ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR, 0,

NULL, "Configuration Failed");

destroy_and_exit_process(process, 1);

}

apr_pool_destroy(ptemp);

for (;;) {

apr_hook_deregister_all();

apr_pool_clear(pconf);

for (mod = ap_prelinked_modules; *mod != NULL; mod++) {

ap_register_hooks(*mod, pconf);

}

/* This is a hack until we finish the code so that it only reads * the config file once and just operates on the tree already in * memory. rbb

*/

ap_conftree = NULL;

apr_pool_create(&ptemp, pconf);

apr_pool_tag(ptemp, "ptemp");

ap_server_root = def_server_root;

/*===========下面这一段是对配置文件进行处理,每次循环都要处理 ==================*/

server_conf = ap_read_config(process, ptemp, confname, &ap_conftree);

if (!server_conf) {

destroy_and_exit_process(process, 1);

}

if (ap_run_pre_config(pconf, plog, ptemp) != OK) {

ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,

0, NULL, "Pre-configuration failed");

destroy_and_exit_process(process, 1);

}

if (ap_process_config_tree(server_conf, ap_conftree, process->pconf,

ptemp) != OK) {

destroy_and_exit_process(process, 1);

}

ap_fixup_virtual_hosts(pconf, server_conf);

ap_fini_vhost_config(pconf, server_conf);

apr_hook_sort_all();

apr_pool_clear(plog);

if (ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) {

ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,

0, NULL, "Unable to open logs");

destroy_and_exit_process(process, 1);

}

if (ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) {

ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,

0, NULL, "Configuration Failed");

destroy_and_exit_process(process, 1);

}

/*===========上面这一段是对配置文件进行处理,每次循环都要处理 ==================*/

apr_pool_destroy(ptemp);

apr_pool_lock(pconf, 1);

ap_run_optional_fn_retrieve();

if (ap_mpm_run(pconf, plog, server_conf)) :如果出错,则跳出循环。

break;

apr_pool_lock(pconf, 0);

} for(;;)在这里结束。

父进程的这个循环,每次都会重新读入配置文件进行处理。然后调用ap_mpm_run()重新生成子进程。 apr_pool_lock(pconf, 0);

destroy_and_exit_process(process, 0);

return 0; /* Termination 'ok' */

}

int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)

{

int index;

int remaining_children_to_start;

apr_status_t rv;

ap_log_pid(pconf, ap_pid_fname);

first_server_limit = server_limit;

if (changed_limit_at_restart) {

ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,

"WARNING: Attempt to change ServerLimit "

"ignored during restart");

changed_limit_at_restart = 0;

}

/* Initialize cross-process accept lock */

ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT,

ap_server_root_relative(_pconf, ap_lock_fname),

ap_my_pid);

rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,

ap_accept_lock_mech, _pconf);

if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {

rv = unixd_set_proc_mutex_perms(accept_mutex);

}

if (!is_graceful) {

if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {

mpm_state = AP_MPMQ_STOPPING;

return 1;

}

/* fix the generation number in the global score; we just got a new,

* cleared scoreboard

*/

ap_scoreboard_image->global->running_generation = ap_my_generation;

}

set_signals(); 这里进行信号量设定,对主进程有效,对子进程有没有效?

Apachectl restart,apachectl stop, apachectl graceful,这些命令将会导致信号处理函数设定如下的全局变量

static int volatile shutdown_pending;

static int volatile restart_pending;

static int volatile is_graceful;

这些变量定义在中。当这些变量发生改变时,程序的流程将发生相应的变化。

if (one_process) {

AP_MONCONTROL(1);

make_child(ap_server_conf, 0);

}

else {

if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */

ap_daemons_max_free = ap_daemons_min_free + 1;

/* If we're doing a graceful_restart then we're going to see a lot

* of children exiting immediately when we get into the main loop

* below (because we just sent them AP_SIG_GRACEFUL). This happens pretty

* rapidly... and for each one that exits we'll start a new one until

* we reach at least daemons_min_free. But we may be permitted to

* start more than that, so we'll just keep track of how many we're

* supposed to start up without the 1 second penalty between each fork.

*/

remaining_children_to_start = ap_daemons_to_start;

if (remaining_children_to_start > ap_daemons_limit) {

remaining_children_to_start = ap_daemons_limit;

}

if (!is_graceful) {

startup_children(remaining_children_to_start);

remaining_children_to_start = 0;

}

else {

/* give the system some time to recover before kicking into

* exponential mode

*/

hold_off_on_exponential_spawning = 10;

}

ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,

"%s configured -- resuming normal operations",

ap_get_server_description());

ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,

"Server built: %s", ap_get_server_built());

#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH

ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,

"AcceptMutex: %s (default: %s)",

apr_proc_mutex_name(accept_mutex),

apr_proc_mutex_defname());

#endif

restart_pending = shutdown_pending = 0;

mpm_state = AP_MPMQ_RUNNING;

while (!restart_pending && !shutdown_pending) { :这里每隔一秒就往返一次。一直进行不停

int child_slot;

apr_exit_why_e exitwhy;

int status, processed_status;

/* this is a memory leak, but I'll fix it later. */

apr_proc_t pid;

ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);

/* XXX: if it takes longer than 1 second for all our children

* to start up and get into IDLE state then we may spawn an

* extra child

*/

if != -1) {

processed_status = ap_process_child_status(&pid, exitwhy, status);

if (processed_status == APEXIT_CHILDFATAL) {

mpm_state = AP_MPMQ_STOPPING;

return 1;

}

/* non-fatal death... note that it's gone in the scoreboard. */

child_slot = find_child_by_pid(&pid);

if (child_slot >= 0) {

(void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,

(request_rec *) NULL);

if (processed_status == APEXIT_CHILDSICK) {

/* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)

* cut the fork rate to the minimum

*/

idle_spawn_rate = 1;

}

else if (remaining_children_to_start

&& child_slot < ap_daemons_limit) {

/* we're still doing a 1-for-1 replacement of dead

* children with new children

*/

make_child(ap_server_conf, child_slot);

如果apachectl graceful,将会执行到这里,在这个循环里每一次都会执行到这里,生成相应的子进程, --remaining_children_to_start;

}

#if APR_HAS_OTHER_CHILD

}

else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) {

/* handled */

#endif

}

else if (is_graceful) {

/* Great, we've probably just lost a slot in the

* scoreboard. Somehow we don't know about this

* child.

*/

ap_log_error(APLOG_MARK, APLOG_WARNING,

0, ap_server_conf,

"long lost child came home! (pid %ld)", (long);

}

/* Don't perform idle maintenance when a child dies,

* only do it when there's a timeout. Remember only a

* finite number of children can die, and it's pretty

* pathological for a lot to die suddenly.

*/

continue;

}

else if (remaining_children_to_start) {

/* we hit a 1 second timeout in which none of the previous

* generation of children needed to be reaped... so assume

* they're all done, and pick up the slack if any is left.

*/

startup_children(remaining_children_to_start);

remaining_children_to_start = 0;

/* In any event we really shouldn't do the code below because

* few of the servers we just started are in the IDLE state

* yet, so we'd mistakenly create an extra server.

*/

continue;

}

perform_idle_server_maintenance(pconf);

}这里while (!restart_pending && !shutdown_pending)结束。

这个循环是父进程执行的,它主要进行子进程的检查。循环的条件是由信号处理,以及对子进行检查的结果来决定的。在启用 apachectl restart命令后,父进程收到SIGHUP received. Attempting to restart信号,收到这个信号后,相应的信号处理函数会设定restart_pending全局变量,导致这个循环结束。这个循环结束后,ap_mpm_run()会进行进行子进程的处理,然后返回0,于是在中的for(;;)循环生效,进行再一次的ap_mpm_run()调用,生成新的子进程,但父进程仍然不变。

} /* one_process */

mpm_state = AP_MPMQ_STOPPING;

if (shutdown_pending && !is_graceful) {

/* Time to shut down:

* Kill child processes, tell them to call child_exit, etc...

*/

if (unixd_killpg(getpgrp(), SIGTERM) < 0) {

ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); }

ap_reclaim_child_processes(1); /* Start with SIGTERM */

/* cleanup pid file on normal shutdown */

{

const char *pidfile = NULL;

pidfile = ap_server_root_relative (pconf, ap_pid_fname);

if ( pidfile != NULL && unlink(pidfile) == 0)

ap_log_error(APLOG_MARK, APLOG_INFO,

0, ap_server_conf,

"removed PID file %s (pid=%ld)",

pidfile, (long)getpid());

}

ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,

"caught SIGTERM, shutting down");

return 1;

} else if (shutdown_pending) {

/* Time to perform a graceful shut down:

* Reap the inactive children, and ask the active ones

* to close their listeners, then wait until they are

* all done to exit.

*/

int active_children;

apr_time_t cutoff = 0;

/* Stop listening */

ap_close_listeners();

/* kill off the idle ones */

ap_mpm_pod_killpg(pod, ap_max_daemons_limit);

/* Send SIGUSR1 to the active children */

active_children = 0;

for (index = 0; index < ap_daemons_limit; ++index) {

if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { /* Ask each child to close its listeners. */

ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL);

active_children++;

}

}

/* Allow each child which actually finished to exit */

ap_relieve_child_processes();

/* cleanup pid file */

{

const char *pidfile = NULL;

pidfile = ap_server_root_relative (pconf, ap_pid_fname);

if ( pidfile != NULL && unlink(pidfile) == 0)

ap_log_error(APLOG_MARK, APLOG_INFO,

0, ap_server_conf,

"removed PID file %s (pid=%ld)",

pidfile, (long)getpid());

}

ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,

"caught " AP_SIG_GRACEFUL_STOP_STRING ", shutting down gracefully"); if (ap_graceful_shutdown_timeout) {

cutoff = apr_time_now() +

apr_time_from_sec(ap_graceful_shutdown_timeout);

}

/* Don't really exit until each child has finished */

shutdown_pending = 0;

do {

/* Pause for a second */

sleep(1);

/* Relieve any children which have now exited */

ap_relieve_child_processes();

active_children = 0;

for (index = 0; index < ap_daemons_limit; ++index) {

if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { active_children = 1;

/* Having just one child is enough to stay around */

break;

}

}

} while (!shutdown_pending && active_children &&

(!ap_graceful_shutdown_timeout || apr_time_now() < cutoff)); /* We might be here because we received SIGTERM, either

* way, try and make sure that all of our processes are

* really dead.

*/

unixd_killpg(getpgrp(), SIGTERM);

return 1;

}

/* we've been told to restart */

apr_signal(SIGHUP, SIG_IGN);

apr_signal(AP_SIG_GRACEFUL, SIG_IGN);

if (one_process) {

/* not worth thinking about */

return 1;

}

/* advance to the next generation */

/* XXX: we really need to make sure this new generation number isn't in

* use by any of the children.

*/

++ap_my_generation;

ap_scoreboard_image->global->running_generation = ap_my_generation;

if (is_graceful) {

ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,

"Graceful restart requested, doing restart");

/* kill off the idle ones */

ap_mpm_pod_killpg(pod, ap_max_daemons_limit);

/* This is mostly for debugging... so that we know what is still

* gracefully dealing with existing request. This will break

* in a very nasty way if we ever have the scoreboard totally

* file-based (no shared memory)

*/

for (index = 0; index < ap_daemons_limit; ++index) {

if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {

ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL;

/* Ask each child to close its listeners.

*

* NOTE: we use the scoreboard, because if we send SIGUSR1

* to every process in the group, this may include CGI's,

* piped loggers, etc. They almost certainly won't handle

* it gracefully.

*/

ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL); }

}

}

else {

/* Kill 'em off */

if (unixd_killpg(getpgrp(), SIGHUP) < 0) {

ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP"); }

ap_reclaim_child_processes(0); /* Not when just starting up */

ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,

"SIGHUP received. Attempting to restart");

}

return 0;

}

这个child_main()函数是重中之重!!!!

static void child_main(int child_num_arg)

{

apr_pool_t *ptrans;

apr_allocator_t *allocator;

apr_status_t status;

int i;

ap_listen_rec *lr;

apr_pollset_t *pollset;

ap_sb_handle_t *sbh;

apr_bucket_alloc_t *bucket_alloc;

int last_poll_idx = 0;

mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this * child initializes

*/

my_child_num = child_num_arg;

ap_my_pid = getpid();

requests_this_child = 0;

ap_fatal_signal_child_setup(ap_server_conf);

/* Get a sub context for global allocations in this child, so that

* we can have cleanups occur when the child exits.

*/

apr_allocator_create(&allocator);

apr_allocator_max_free_set(allocator, ap_max_mem_free);

apr_pool_create_ex(&pchild, pconf, NULL, allocator);

apr_allocator_owner_set(allocator, pchild);

apr_pool_create(&ptrans, pchild);

apr_pool_tag(ptrans, "transaction");

/* needs to be done before we switch UIDs so we have permissions */

ap_reopen_scoreboard(pchild, NULL, 0);

status = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild); if (status != APR_SUCCESS) {

ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf,

"Couldn't initialize cross-process lock in child "

"(%s) (%d)", ap_lock_fname, ap_accept_lock_mech);

clean_child_exit(APEXIT_CHILDFATAL);

}

if (unixd_setup_child()) {

clean_child_exit(APEXIT_CHILDFATAL);

}

ap_run_child_init(pchild, ap_server_conf);

ap_create_sb_handle(&sbh, pchild, my_child_num, 0);

(void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);

/* Set up the pollfd array */

/* ### check the status */

(void) apr_pollset_create(&pollset, num_listensocks, pchild, 0);

for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) {

apr_pollfd_t pfd = { 0 };

= APR_POLL_SOCKET;

= lr->sd;

= APR_POLLIN;

= lr;

/* ### check the status */

(void) apr_pollset_add(pollset, &pfd);

}

mpm_state = AP_MPMQ_RUNNING;

bucket_alloc = apr_bucket_alloc_create(pchild);

/* die_now is set when AP_SIG_GRACEFUL is received in the child;

* shutdown_pending is set when SIGTERM is received when running

* in single process mode. */

while (!die_now && !shutdown_pending) {

conn_rec *current_conn;

void *csd;

/*

* (Re)initialize this child to a pre-connection state.

*/

apr_pool_clear(ptrans); 第一次执行

if ((ap_max_requests_per_child > 0

&& requests_this_child++ >= ap_max_requests_per_child)) {

clean_child_exit(0);

}

(void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); /*

* Wait for an acceptable connection to arrive.

*/

/* Lock around "accept", if necessary */

SAFE_ACCEPT(accept_mutex_on());

if (num_listensocks == 1) {

/* There is only one listener record, so refer to that one. */

lr = ap_listeners; 第一次执行

}

else { 第一次没有执行这里,因为只有一个socket监听

/* multiple listening sockets - need to poll */

for (;;) {

apr_int32_t numdesc;

const apr_pollfd_t *pdesc;

/* timeout == -1 == wait forever */

status = apr_pollset_poll(pollset, -1, &numdesc, &pdesc);

if (status != APR_SUCCESS) {

if (APR_STATUS_IS_EINTR(status)) {

if (one_process && shutdown_pending) {

return;

}

else if (die_now) {

/* In graceful stop/restart; drop the mutex

* and terminate the child. */

SAFE_ACCEPT(accept_mutex_off());

clean_child_exit(0);

}

continue;

}

/* Single Unix documents select as returning errnos

* EBADF, EINTR, and EINVAL... and in none of those

* cases does it make sense to continue. In fact

* on Linux we seem to end up with EFAULT

* occasionally, and we'd loop forever due to it.

*/

ap_log_error(APLOG_MARK, APLOG_ERR, status,

ap_server_conf, "apr_pollset_poll: (listen)"); SAFE_ACCEPT(accept_mutex_off());

clean_child_exit(1);

}

/* We can always use pdesc[0], but sockets at position N

* could end up completely starved of attention in a very

* busy server. Therefore, we round-robin across the

* returned set of descriptors. While it is possible that

* the returned set of descriptors might flip around and

* continue to starve some sockets, we happen to know the

* internal pollset implementation retains ordering

* stability of the sockets. Thus, the round-robin should

* ensure that a socket will eventually be serviced.

*/

if (last_poll_idx >= numdesc)

last_poll_idx = 0;

/* Grab a listener record from the client_data of the poll

* descriptor, and advance our saved index to round-robin

* the next fetch.

*

* ### hmm... this descriptor might have POLLERR rather

* ### than POLLIN

*/

lr = pdesc[last_poll_idx++].client_data;

goto got_fd;

}

}

got_fd:

/* if we accept() something we don't want to die, so we have to

* defer the exit

*/

status = lr->accept_func(&csd, lr, ptrans); 子进程会在这里等待。如果有访问,就会执行这一句。

SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */

if (status == APR_EGENERAL) {

/* resource shortage or should-not-occur occured */

clean_child_exit(1);

}

else if (status != APR_SUCCESS) {

continue;

}

/*

* We now have a connection, so set it up with the appropriate

* socket options, file descriptors, and read/write buffers.

*/

current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); 如果有client访问,会执行到这里。

if (current_conn) {

ap_process_connection(current_conn, csd); 如果有client访问,会执行到这里。在/server/里有定义。

ap_lingering_close(current_conn); 如果有client访问,会执行到这里。??

}

/* Check the pod and the generation number after processing a

* connection so that we'll go away if a graceful restart occurred

* while we were processing the connection or we are the lucky

* idle server process that gets to die.

*/

if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */

die_now = 1;

}

else if (ap_my_generation !=

ap_scoreboard_image->global->running_generation) { /* restart? */

/* yeah, this could be non-graceful restart, in which case the

* parent will kill us soon enough, but why bother checking?

*/

die_now = 1;

}

}

clean_child_exit(0);

Red Hat Enterprise Linux AS release 3 (Taroon Update 4)

2.4.21

root]# /usr/apache2/bin/httpd -V

Server version: Apache/2.0.53

Server built: Sep 9 2005 16:27:28

Server's Module Magic Number: :9

Architecture: 32-bit

Server compiled with....

-D APACHE_MPM_DIR="server/mpm/prefork"

-D APR_HAS_SENDFILE

-D APR_HAS_MMAP

-D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)

-D APR_USE_SYSVSEM_SERIALIZE

-D APR_USE_PTHREAD_SERIALIZE

-D SINGLE_LISTEN_UNSERIALIZED_ACCEPT

-D APR_HAS_OTHER_CHILD

-D AP_HAVE_RELIABLE_PIPED_LOGS

-D HTTPD_ROOT="/usr/apache2"

-D SUEXEC_BIN="/usr/apache2/bin/suexec"

-D DEFAULT_PIDLOG="log"

-D DEFAULT_SCOREBOARD="logs/apache_runtime_status"

-D DEFAULT_LOCKFILE="logs/"

-D DEFAULT_ERRORLOG="logs/error_log"

-D AP_TYPES_CONFIG_FILE="conf/"

-D SERVER_CONFIG_FILE="conf/"

故障现象:

在Linux AS 3上使用压力测试工具进行测试有时出现httpd子进程CPU占用率100%,且压力撤除后无法恢复,始终有个别httpd子进程CPU占用率很高。但在 Linux AS 4上测试始终不会出现此问题,另外使用Jmeter测试在两种系统上均未出现该现象。

问题初步分析:

由于在Linux AS 4上未出现问题,所以可以确定测试工具和测试脚本不会存在问题。打开Apache 监视页面发现CPU占用率高的子进程的状态为Reading,在 Apache官方Bugzilla上也有人出现的同样的问题不过有一例已经解决(是由于自身模块的原因,但是没有具体说明)。

问题的进一步分析:

由于不能通过一些外部表现来继续跟踪,所以只能借助于GDB了。在Apache帮助中有调试相关的介绍,所以就按部就班当故障出现时使用GDB把故障进程的调用堆栈显示出来(如下):

(gdb) bt

#0 0x002738a0 in _IO_un_link_internal () from /lib/tls/

#1 0x0027496c in _IO_default_finish_internal () from /lib/tls/

#2 0x002713ad in _IO_new_file_finish () from /lib/tls/

#3 0x002666d5 in () from /lib/tls/

#4 0x004f3523 in CPakReader::Close () from /usr/lib/httpd/modules/

#5 0x004f2c50 in CPakReader::~CPakReader () from /usr/lib/httpd/modules/

#6 0x004f3e29 in mod_pak_method_handler () from /usr/lib/httpd/modules/

#7 0x0807c2f2 in ap_run_handler (r=0x8a56518) at :153

#8 0x0807c80a in ap_invoke_handler (r=0x8a56518) at :364

#9 0x0806bf8f in ap_process_request (r=0x8a56518) at :249

#10 0x08068049 in ap_process_http_connection (c=0x8a523e0) at :251

#11 0x0808556e in ap_run_process_connection (c=0x8a523e0) at :43

#12 0x0807ae6b in child_main (child_num_arg=0) at :610

#13 0x0807af88 in make_child (s=0x897f800, slot=0) at :704

#14 0x0807b06f in startup_children (number_to_start=5) at :722

#15 0x0807b77d in ap_mpm_run (_pconf=0x897b0a8, plog=0x89b3188, s=0x897f800) at :941

#16 0x08080732 in main (argc=1, argv=0xbfffb324) at :618

接着就是在调用堆栈中自己的模块和相关的函数,然后针对调试该函数,输出更详细的错误信息。此例中出现故障的httpd进程在C库的fclose调用内部可能发生了一个未结束的循环,由于该故障在AS4环境下不存在,据此推定可能是glibc的线程局域存储实现在AS3特有的NPTL环境下有BUG而在某个边界条件下被触发,由堆栈信息可知引发该故障的原因是CPakReader对象析构时调用的fclose,通过增加调试代码发现该处fclose返回了 -1(EOF),基本判定为重复关闭已关闭的FILE流指针引发了该故障,因此马上修改后重新测试,问题得以修正。

经验总结:

1、测试时尽量多采用不同的测试工具进行测试,避免由于测试工具的缺陷导致问题潜藏在系统中;

2、对于不经常出现的问题和故障,在发生时尽量保留现场进行分析,并详细记录每次测试的配置条件

3、由于资源泄露和过度释放属代码中高频度发生的BUG,建议开发人员引入一些必要的自动化源代码扫描覆盖手段,尽可能提前发现此类BUG;

4、由于的核心在原生内核线程支持、进程调度抢占及代码维护等级等方面均优于核心,且JAVA支持也更加高效,应用部署平台如无特殊要求请尽量使用AS4等使用发行版(比较高的版本)。

android系统开机启动流程分析

一,系统引导bootloader 加电,cpu执行bootloader程序,正常启动系统,加载boot.img【其中包含内核。还有ramdisk】 二,内核kernel bootloader加载kernel,kernel自解压,初始化,载入built-in驱动程序,完成启动。 内核启动后会创建若干内核线程,在后装入并执行程序/sbin/init/,载入init process,切换至用户空间(user-space) 内核zImage解压缩 head.S【这是ARM-Linux运行的第一个文件,这些代码是一个比较独立的代码包裹器。其作用就是解压Linux内核,并将PC指针跳到内核(vmlinux)的第一条指令】首先初始化自解压相关环境(内存等),调用decompress_kernel进行解压,解压后调用start_kernel启动内核【start_kernel是任何版本linux内核的通用初始化函数,它会初始化很多东西,输出linux版本信息,设置体系结构相关的环境,页表结构初始化,设置系 统自陷入口,初始化系统IRQ,初始化核心调度器等等】,最后调用rest_init【rest_init 会调用kernel_init启动init进程(缺省是/init)。然后执行schedule开始任务调度。这个init是由android的./system/core/init下的代码编译出来的,由此进入了android的代码】。 三,Init进程启动 【init是kernel启动的第一个进程,init启动以后,整个android系统就起来了】 init进程启动后,根据init.rc 和init. .rc脚本文件建立几个基本 服务(servicemanager zygote),然后担当property service 的功能 打开.rc文件,解析文件内容。【system/core/init/init.c】将service信息放置到service.list中【system/core/init/init_parser.c】。 建立service进程。【service_start(…) execve(…)】 在init.c中,完成以下工作 1、初始化log系统【解析/init.rc和init.%hardware%.rc文件,在两个 文件解析步骤2时执行“early-init”行动】 2、初始化设备【在/dev下创建所有设备节点,下载firmwares】 3、初始化属性服务器【在两个文件解析步骤2时执行“init”行动】

详解bootloader的执行流程与ARM Linux启动过程分析

详解bootloader的执行流程与ARM Linux启动过程分析 ARM Linux启动过程分析是本文要介绍的内容,嵌入式Linux 的可移植性使得我们可以在各种电子产品上看到它的身影。对于不同体系结构的处理器来说Linux的启动过程也有所不同。 本文以S3C2410 ARM处理器为例,详细分析了系统上电后bootloader的执行流程及ARM Linux的启动过程。 1、引言 Linux 最初是由瑞典赫尔辛基大学的学生Linus Torvalds在1991 年开发出来的,之后在GNU的支持下,Linux 获得了巨大的发展。虽然Linux 在桌面PC 机上的普及程度远不及微软的Windows 操作系统,但它的发展速度之快、用户数量的日益增多,也是微软所不能轻视的。而近些年来Linux 在嵌入式领域的迅猛发展,更是给Linux 注入了新的活力。 一个嵌入式Linux 系统从软件角度看可以分为四个部分:引导加载程序(bootloader),Linux 内核,文件系统,应用程序。 其中bootloader是系统启动或复位以后执行的第一段代码,它主要用来初始化处理器及外设,然后调用Linux 内核。 Linux 内核在完成系统的初始化之后需要挂载某个文件系统做为根文件系统(Root Filesystem)。 根文件系统是Linux 系统的核心组成部分,它可以做为Linux 系统中文件和数据的存储区域,通常它还包括系统配置文件和运行应用软件所需要的库。 应用程序可以说是嵌入式系统的“灵魂”,它所实现的功能通常就是设计该嵌入式系统所要达到的目标。如果没有应用程序的支持,任何硬件上设计精良的嵌入式系统都没有实用意义。 从以上分析我们可以看出bootloader 和Linux 内核在嵌入式系统中的关系和作用。Bootloader在运行过程中虽然具有初始化系统和执行用户输入的命令等作用,但它最根本

Android 开机启动流程

Android的开机流程 1. 系统引导bootloader 1) 源码:bootable/bootloader/* 2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.i mg包含内核,基本的文件系统,用于工程模式的烧写 c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况) 2. 内核kernel 1) 源码:kernel/* 2) 说明:kernel由bootloader加载 3. 文件系统及应用init 1) 源码:system/core/init/* 2) 配置文件:system/rootdir/init.rc, 3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1)源码:frameworks/base/cmds/app_main.cpp等 2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process a)建立Java Runtime,建立虚拟机 b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序 c) 启动System Server 5. 系统服务system server 1)源码:frameworks/base/services/java/com/android/server/SystemServer.jav a 2) 说明:被zygote启动,通过SystemManager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等) 6. 桌面launcher 1)源码:ActivityManagerService.java为入口,packages/apps/launcher*实现 2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用()启launcher 7. 解锁 1) 源码: frameworks/policies/base/phone/com/android/internal/policy/impl/*lock* 2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

分析Android 开机启动慢的原因

开机启动花了40多秒,正常开机只需要28秒就能开机起来。 内核的启动我没有去分析,另一个同事分析的。我主要是分析从SystemServer启来到开机动画结束显示解锁界面的这段时间,也就是开机动画的第三个动画开始到结束这段时间,这是个比较耗时阶段,一般都在17秒左右(见过牛B的手机,只需5秒)。 SystemServer分两步执行:init1和init2。init1主要是初始化native的服务,代码在sy stem_init.cpp的system_init,初始化了SurfaceFlinger和SensorService这两个native的服务。init2启动的是java的服务,比如ActivityManagerService、WindowManagerService、PackageManagerService等,在这个过程中PackageManagerService用的时间最长,因为PackageManagerService会去扫描特定目录下的jar包和apk文件。 在开机时间需要40多秒的时,从Log上可以看到,从SurfaceFlinger初始化到动画结束,要27秒左右的时间,即从SurfaceFlinger::init的LOGI("SurfaceFlinger is starting")这句Log到void SurfaceFlinger::bootFinished()的LOGI("Boot is finished (%ld ms)", long(ns 2ms(duration)) ),需要27秒左右的时间,这显然是太长了,但到底是慢在哪了呢?应该在个中间的点,二分一下,于是想到了以启动服务前后作为分隔:是服务启动慢了,还是在服务启动后的这段时间慢?以ActivityManagerService的Slog.i(TAG, "System now ready")的这句Log为分割点,对比了一下,在从SurfaceFlinger is starting到System now read y多了7秒左右的时间,这说明SystemServer在init1和init2过程中启动慢了,通过排查,发现在init1启动的时候,花了7秒多的时间,也就是system_init的LOGI("Entered system _init()")到LOGI("System server: starting Android runtime.\n")这段时间用了7秒多,而正常情况是400毫秒便可以初始化完,通过添加Log看到,在SensorService启动时,用了比较长的时间。 不断的添加Log发现,在启动SensorService时候,关闭设备文件变慢了,每次关闭一个/dev/input/下的设备文件需要100ms左右,而SensorService有60~70次的关闭文件,大概有7s左右的时间。 调用流程是: frameworks/base/cmds/system_server/library/system_init.cpp: system_init->SensorServi ce::instantiate frameworks/native/services/sensorservice/SensorService.cpp: void SensorService::onFi rstRef()->SensorDevice& dev(SensorDevice::getInstance()) hardware/libsensors/SensorDevice.cpp: SensorDevice::SensorDevice()->sensors_open hardware/libsensors/sensors.cpp: open_sensors->sensors_poll_context_t sensors_poll_context_t执行打开每个传感器设备时,遍历/dev/input/目录下的设备文件,以匹配当前需要打开的设备,遍历文件是在 hardware/libsensors/SensorBase.cpp的openInput下实现,如果打开的设备文件不是正在打开的设备文件,会执行下面语句的else部分: if (!strcmp(name, inputName)) { strcpy(input_name, filename); break;

Apache服务器的安装与配置

Apache服务器的安装与配置 一、安装Apache 双击可执行文件apache_1.3.33-win32-x86-no_src.exe,将Apache服务器软件安装至C:\Apache目录下。 二、设置C:\apache\conf\httpd.donf文件 修改Apache的核心配置文件c:\apache\conf\httpd.conf(说明一点:“#”为Apache的注释符号)。修改方法如下: 1、寻找到ServerName。这里定义你的域名。这样,当Apache Server运行时,你可以在浏览器中访问自己的站点。如果前面有#,记得删除它。 2、寻找到ServerAdmin。这里输入你的E-Mail地址。 (以上两条在安装时应该已经配置好了,所以不必改动,这里介绍一下,主要是为了日后的修改) 3、寻找到。向下有一句Options,去掉后面所有的参数,加一个All(注意区分大小写!A 大写,两个l小写。下同。);接着还有一句Allow Override,也同样去掉后面所有的参数,加一个All。 AllowOverride All Options All Order allow,deny Allow from all 4、寻找到DocumentRoot。这个语句指定你的网站路径,也就是你主页放置的目录。你可以使用默认的,也可以自己指定一个,但记住,这句末尾不要加“/”。此外注意,路径的分隔符在Apache Server里写成“/”。(将DocumentRoot "C:/apache/htdocs"改为DocumentRoot "C:/try") 5、寻找到DirectoryIndex。这就是你站点第一个显示的主页,在index.html的后面加入index.htm index.php index.php3 index.cgi index.pl。注意,每种类型之间都要留一空格!这里添加好了,以后就不用再麻烦了。 6、port(端口号),如果没安装IIS的话,就保持80不要变,否则,就要改一下(因为IIS的WEB服务占据了80),可以改成81等等。 三、Apache的手动启动和停止 Net start apache启动apache服务,Net stop apache停止apache服务。

基于MT6752的 android 系统启动流程分析报告

基于MT6752的Android系统启动流程分析报告 1、Bootloader引导 (2) 2、Linux内核启动 (23) 3、Android系统启动 (23) 报告人: 日期:2016.09.03

对于Android整个启动过程来说,基本可以划分成三个阶段:Bootloader引导、Linux kernel启动、Android启动。但根据芯片架构和平台的不同,在启动的Bootloader阶段会有所差异。 本文以MTK的MT6752平台为例,分析一下基于该平台的Android系统启动流程。 1、Bootloader引导 1.1、Bootloader基本介绍 BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备,目的就是引导linux操作系统及Android框架(framework)。 它的主要功能包括设置处理器和内存的频率、调试信息端口、可引导的存储设备等等。在可执行环境创建好之后,接下来把software装载到内存并执行。除了装载software,一个外部工具也能和bootloader握手(handshake),可指示设备进入不同的操作模式,比如USB下载模式和META模式。就算没有外部工具的握手,通过外部任何组合或是客户自定义按键,bootloader也能够进入这些模式。 由于不同处理器芯片厂商对arm core的封装差异比较大,所以不同的arm处理器,对于上电引导都是由特定处理器芯片厂商自己开发的程序,这个上电引导程序通常比较简单,会初始化硬件,提供下载模式等,然后才会加载通常的bootloader。 下面是几个arm平台的bootloader方案: marvell(pxa935) : bootROM + OBM + BLOB informax(im9815) : bootROM + barbox + U-boot mediatek(mt6517) : bootROM + pre-loader + U-boot broadcom(bcm2157) : bootROM + boot1/boot2 + U-boot 而对MT6752平台,MTK对bootloader引导方案又进行了调整,它将bootloader分为以下两个部分: (1) 第1部分bootloader,是MTK内部(in-house)的pre-loader,这部分依赖平台。 (2) 第2部分bootloader,是LK(little kernel的缩写,作用同常见的u-boot差不多),这部分依赖操作系统,负责引导linux操作系统和Android框架。 1.2、bootloader的工作流程 1.2.1 bootloader正常的启动流程 先来看启动流程图:

apache服务器启动失败的解决方法

安装apache之后,桌面右下角出现apache是红色的,这意味着apache没有启动,鼠 标移至任务栏Apache 服务图标显示“No services installed”,解决方法: 1.找到你的apache服务器的安装目录(我的安装目录在E盘) 2.点击电脑左下角“开始”→“运行”→输入“cmd”→默认是C:\Documents and Settings\Administrator> 3.现在我们将默认C:\Documents and Settings\Administrator>改为我们的Apache安装目录,命令如下:C:\Documents and Settings\Administrator>E:按回车键,然后键入安装目录中的bin地址: E:\>cd E:\Apache2.2\bin 按回车键,然后键入命令添加apache服务器: E:\>cd E:\Apache2.2\bin>httpd.exe -k install -n apache2 好了,现在我们已经添加apache这个服务了,接下来是启动服务(net start apache2):E:\>cd E:\Apache2.2\bin>net start apache2 然后按回车键,apache服务器就启动了。 卸载apache的命令是:E:\>cd E:\Apache2.2\bin>httpd -k uninstall(卸载apache) 最后测试apache是否安装成功,在IE地址栏输入:http://localhost:8080/(我的端口是8080)如果端口号是80则不用加端口号,直接在地址栏输入http://localhost/ 如果页面中出现“It Works”,则意味着你的apache安装成功了。

Apache服务器配置技巧

1、如何设置请求等待时间 在httpd.conf里面设置: TimeOut n 其中n为整数,单位是秒。 设置这个TimeOut适用于三种情况: 2、如何接收一个get请求的总时间 接收一个post和put请求的TCP包之间的时间 TCP包传输中的响应(ack)时间间隔 3、如何使得apache监听在特定的端口 修改httpd.conf里面关于Listen的选项,例如: Listen 8000 是使apache监听在8000端口 而如果要同时指定监听端口和监听地址,可以使用: Listen 192.170.2.1:80 Listen 192.170.2.5:8000 这样就使得apache同时监听在192.170.2.1的80端口和192.170.2.5的8000端口。 当然也可以在httpd.conf里面设置: Port 80 这样来实现类似的效果。 4、如何设置apache的最大空闲进程数 修改httpd.conf,在里面设置: MaxSpareServers n 其中n是一个整数。这样当空闲进程超过n的时候,apache主进程会杀掉多余的空闲进程而保持空闲进程在n,节省了系统资源。如果在一个apache非常繁忙的站点调节这个参数才是必要的,但是在任何时候把这个参数调到很大都不是一个好主意。 同时也可以设置: MinSpareServers n 来限制最少空闲进程数目来加快反应速度。 5、apache如何设置启动时的子服务进程个数 在httpd.conf里面设置: StartServers 5 这样启动apache后就有5个空闲子进程等待接受请求。 也可以参考MinSpareServers和MaxSpareServers设置。 6、如何在apache中设置每个连接的最大请求数 在httpd.conf里面设置: MaxKeepAliveRequests 100 这样就能保证在一个连接中,如果同时请求数达到100就不再响应这个连接的新请求,保证了系统资源不会被某个连接大量占用。但是在实际配置中要求尽量把这个数值调高来获得较高的系统性能。 7、如何在apache中设置session的持续时间 在apache1.2以上的版本中,可以在httpd.conf里面设置: KeepAlive on KeepAliveTimeout 15 这样就能限制每个session的保持时间是15秒。session的使用可以使得很多请求都可以通过同一个tcp

Android开机启动流程样本

Android的开机流程 1. 系统引导bootloader 1) 源码: bootable/bootloader/* 2) 说明: 加电后, CPU将先执行bootloader程序, 此处有三种选择 a) 开机按Camera+Power启动到fastboot, 即命令或SD卡烧写模式, 不加载内核及文件系统, 此处能够进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式, 加载recovery.img, recovery.img包含内核, 基本的文件系统, 用于工程模式的烧写 c) 开机按Power, 正常启动系统, 加载boot.img, boot.img包含内核, 基本文件系统, 用于正常启动手机( 以下只分析正常启动的情况) 2. 内核kernel 1) 源码: kernel/* 2) 说明: kernel由bootloader加载 3. 文件系统及应用init 1) 源码: system/core/init/* 2) 配置文件: system/rootdir/init.rc, 3) 说明: init是一个由内核启动的用户级进程, 它按照init.rc中的设置执行: 启动服务( 这里的服务指linux底层服务, 如adbd提供adb支持, vold提供SD卡挂载等) , 执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1) 源码: frameworks/base/cmds/app_main.cpp等 2) 说明: zygote是一个在init.rc中被指定启动的服务, 该服务对应的命令是/system/bin/app_process

linux grub 引导启动过程详解

linux grub 引导启动过程详解 2008-01-08 17:18 这几天看了很多文档,算是对linux的启动过程有了比较细致的了解. 网上有很多文章谈到这方面的内容,但总觉得没有一篇完全的解析linux启动的 细节,下面是我小弟在学习的过程中总结出来的一些东东.这个是完整的linux启动过程, 不涉及内核,但是我觉得比较详细哦. (由于本人比较懒,这一段是从网上抄的) 机器加电启动后,BIOS开始检测系统参数,如内存的大小,日期和时间,磁盘 设备以及这些磁盘设备用来引导的顺序,通常情况下,BIOS都是被配置成首先检查 软驱或者光驱(或两者都检查),然后再尝试从硬盘引导。如果在这些可移动的设 备中,没有找到可引导的介质,那么BIOS通常是转向第一块硬盘最初的几个扇区, 寻找用于装载操作系统的指令。装载操作系统的这个程序就是boot loader. linux里面的boot loader通常是lilo或者grub,从Red Hat Linux 7.2起,GRUB( GRand Unified Bootloader)取代LILO成为了默认的启动装载程序。那么启动的时候grub是如何被载入的呢 grub有几个重要的文件,stage1,stage2,有的时候需要stage1.5.这些文件一般都 在/boot/grub文件夹下面.grub被载入通常包括以下几个步骤: 1. 装载基本的引导装载程序(stage1),stage1很小,网上说是512字节,但是在我的系统上用du -b /boot/grub/stage1 显示的是1024个字节,不知道是不是grub版本不同的缘故还是我理解有误.stage1通常位于主引导扇区里面,对于硬盘就是MBR了,stage1的主要功能就是装载第二引导程序(stage2).这主要是归结于在主引导扇区中没有足够的空间用于其他东西了,我用的是grub 0.93,stage2文件的大小是107520 bit. 2. 装载第二引导装载程序(stage2),这第二引导装载程序实际上是引出更高级的功能, 以允许用户装载入一个特定的操作系统。在GRUB中,这步是让用户显示一个菜单或是输入命令。由于stage2很大,所以它一般位于文件系统之中(通常是boot所在的根 分区). 上面还提到了stage1.5这个文件,它的作用是什么呢你到/boot/grub目录下看看, fat_stage_1.5 e2fs_stage_1.5 xfs_stage_1.5等等,很容易猜想stage1.5和文件系统 有关系.有时候基本引导装载程序(stage1)不能识别stage2所在的文件系统分区,那么这 时候就需要stage1.5来连接stage1和stage2了.因此对于不同的文件系统就会有不同的stage1.5.但是对于grub 0.93好像stage1.5并不是很重要,因为我试过了,在没有stage1.5 的情况下, 我把stage1安装在软盘的引导扇区内,然后把stage2放在格式化成ext2或者fat格式的软盘内,启动的时候照常引导,并不需要e2fs_stage_1.5或者fat_stage_1.5. 下面是我的试验: #mkfs.ext2 /dev/fd0 #mount -t ext2 /dev/fd0 /mnt/floppy #cd /mnt/floppy #mkdir boot #cd boot #mkdir grub (以上三步可用mkdir -p boot/grub命令完成) #cd grub #cp /boot/grub/{stage1,stage2,grub.conf} ./ #cd; umount /mnt/floppy

Apache启动失败 启动又停止解决方案

1、apache启动失败出错显示: Godisu>net start apache2. The Apache2.2 service is starting. The Apache2.2 service could not be started. The service did not report an error. More help is available by typing NET HELPMSG 3534. 2、查看apache日志: [Thu Dec 23 08:43:06 2010] [notice] Apache/2.2.4 (Win32) PHP/5.2.3 configured -- resuming normal operations [Thu Dec 23 08:43:06 2010] [notice] Server built: Jan 9 2007 23:17:20 [Thu Dec 23 08:43:06 2010] [notice] Parent: Created child process 3820 [Thu Dec 23 08:43:06 2010] [notice] Child 3820: Child process is running [Thu Dec 23 08:43:06 2010] [crit] (OS 10022)提供了一个无效的参数。: Child 3820: setup_inherited_listeners(), WSASocket failed to open the inherited socket. [Thu Dec 23 08:43:06 2010] [crit] Parent: child process exited with status 3 -- Aborting. 3、解决方法: 打开本地连接的TCP/IP属性下的Wins 去掉勾选LMHOSTS查询 NetBIOS设置选择“启用TCP/IP上的NETBIOS” 4、再次启动apache服务: Godisu>net start apach The Apache2.2 service is starting. The Apache2.2 service was started successfully. 服务已经启动成功了。 5、再次查看apache日志: [Thu Dec 23 08:43:06 2010] [crit] Parent: child process exited with status 3 -- Aborting. [Thu Dec 23 08:44:56 2010] [notice] Apache/2.2.4 (Win32) PHP/5.2.3 configured -- resuming normal operations [Thu Dec 23 08:44:56 2010] [notice] Server built: Jan 9 2007 23:17:20 [Thu Dec 23 08:44:56 2010] [notice] Parent: Created child process 2424 [Thu Dec 23 08:44:56 2010] [notice] Child 2424: Child process is running [Thu Dec 23 08:44:56 2010] [notice] Child 2424: Acquired the start mutex. [Thu Dec 23 08:44:56 2010] [notice] Child 2424: Starting 64 worker threads. [Thu Dec 23 08:44:56 2010] [notice] Child 2424: Starting thread to listen on port 80. [Thu Dec 23 08:44:56 2010] [notice] Child 2424: Starting thread to listen on port 8080. 日志显示启动正常,打开浏览器输入服务器域名或IP,测试网页OK 已经全部OK。完毕!~

Android SystemBar启动流程分析

Android SystemBar启动流程分析 SystemBars的服务被start时,最终会调用该类的onNoService()方法。 @Override public void start() { if (DEBUG) Log.d(TAG, "start"); ServiceMonitor mServiceMonitor = new ServiceMonitor(TAG, DEBUG, mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this); mServiceMonitor.start(); // will call onNoService if no remote service is found } @Override public void onNoService() { if (DEBUG) Log.d(TAG, "onNoService"); createStatusBarFromConfig(); // fallback to using an in-process implementation } private void createStatusBarFromConfig() { … mStatusBar = (BaseStatusBar) cls.newInstance(); … mStatusBar.start(); } BaseStatusBar是一个抽象类,故调用其子类的PhoneStatusBar的start 函数。 @Override public void start() { … super.start(); … } 子类的start又调用了父类的start public void start() { … createAndAddWindows(); … }

Linux启动全过程-由bootloader到fs

Linux启动过程 许多人对Linux的启动过程感到很神秘,因为所有的启动信息都在屏幕上一闪而过。其实Linux的启动过程并不象启动信息所显示的那样复杂,它主要分成两个阶段: 1.启动内核。在这个阶段,内核装入内存并在初始化每个设备驱动器时打印信息。 2.执行程序init。装入内核并初始化设备后,运行init程序。init程序处理所有程序的启动, 包括重要系统精灵程序和其它指定在启动时装入的软件。 下面以Red Hat为例简单介绍一下Linux的启动过程。 一、启动内核 首先介绍启动内核部分。电脑启动时,BIOS装载MBR,然后从当前活动分区启动,LILO获得引导过程的控制权后,会显示LILO提示符。此时如果用户不进行任何操作,LILO将在等待制定时间后自动引导默认的操作系统,而如果在此期间按下TAB键,则可以看到一个可引导的操作系统列表,选择相应的操作系统名称就能进入相应的操作系统。当用户选择启动LINUX操作系统时,LILO就会根据事先设置好的信息从ROOT文件系统所在的分区读取LINUX映象,然后装入内核映象并将控制权交给LINUX内核。LINUX内核获得控制权后,以如下步骤继续引导系统: 1. LINUX内核一般是压缩保存的,因此,它首先要进行自身的解压缩。内核映象前面的一些代码完成解压缩。 2. 如果系统中安装有可支持特殊文本模式的、且LINUX可识别的SVGA卡,LINUX会提示用户选择适当的文本显示模式。但如果在内核的编译过程中预先设置了文本模式,则不会提示选择显示模式。该显示模式可通过LILO或RDEV工具程序设置。 3. 内核接下来检测其他的硬件设备,例如硬盘、软盘和网卡等,并对相应的设备驱动程序进行配置。这时,显示器上出现内核运行输出的一些硬件信息。 4. 接下来,内核装载ROOT文件系统。ROOT文件系统的位置可在编译内核时指定,也可通过LILO 或RDEV指定。文件系统的类型可自动检测。如果由于某些原因装载失败,则内核启动失败,最终会终止系统。 二、执行init程序 其次介绍init程序,利用init程序可以方便地定制启动其间装入哪些程序。init的任务是启动新进程和退出时重新启动其它进程。例如,在大多数Linux系统中,启动时最初装入六个虚拟的控制台进程,退出控制台窗口时,进程死亡,然后init启动新的虚拟登录控制台,因而总是提供六个虚拟登陆控控制台进程。控制init程序操作的规则存放在文件/etc/inittab中。Red Hat Linux缺省的inittab文件如下:# #inittab This file describes how the INIT process should set up the system in a certain #run-level. # # #Default runlevel.The runlevels used by RHS are: #0-halt(Do NOT set initdefault to this) #1-Single user mode #2-Multiuser,without NFS(the same as 3,if you do not have networking) #3-Full multiuser mode #4-unused #5-X11 #6-reboot(Do NOT set initdefault to this)

Apache与tomcat的整合、负载均衡和加入启动和系统服务

Apache与tomcat的整合、负载均衡和加入启动 和系统服务 系统环境:Windows Server 2008 R2 SP1 虚拟机软件:Hyper-V治理器6.1.7601.17514 虚拟机环境:Red Hat Enterprise Linux Server release 5.4 (Tikanga) X64 安装软件版本:JDK:1.6.0_19 Tomcat:6.0.20 Apache:2.2.19 JK: 1.2.10实施步骤: 一、安装软件。。。 tar -xzvf jdk1.6.0_19.tar.gz tar xvfz tomcat.tar.gz tar zxvf httpd-2.2.19.tar.gz cd httpd-2.2.19 ./configure --prefix=/usr/local/apache2 --enable-so --enable-mods-shared =most --with-mpm=worker make make install tar zxvf jakarta-tomcat-connectors-1.2.10-src.tar.gz cd jakarta-tomcat-connectors-1.2.10-src/jk/native/ ./buildconf.sh ./configure --with-apxs=/usr/local/apache2/bin/apxs make make install 二、配置整合及负载均衡 1 cp /usr/local/jakarta-tomcat-connectors-1.2.10-src/jk/native/apache-2.0/ mod_jk.so /usr/local/apache2/modules 配置环境变量 vi /etc/profile 在文本末尾加入以下内容

Android系统启动过程详解

Android系统启动过程详解 Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用。 启动的过程如下图所示:(图片来自网上,后面有地址)

下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码片段中均有省略不完整,请参照源码。

一Init进程的启动 init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行, 并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。 启动过程就是代码init.c中main函数执行过程:system\core\init\init. c 在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket监听…… 下面看两个重要的过程:rc文件解析和服务启动。 1 rc文件解析 .rc文件是Android使用的初始化脚本文件(System/Core/Init/readm e.txt中有描述: four broad classes of statements which are Actions, Commands, Services, and Options.) 其中Command 就是系统支持的一系列命令,如:export,hostname,mkdir,mount,等等,其中一部分是linux 命令, 还有一些是android 添加的,如:class_start :启动服务,class_stop :关闭服务,等等。 其中Options是针对Service 的选项的。 系统初始化要触发的动作和要启动的服务及其各自属性都在rc脚本文件中定义。具体看一下启动脚本:\system\core\rootdir\init.rc 在解析rc脚本文件时,将相应的类型放入各自的List中: \system\core\init\Init_parser.c :init_parse_config_file( )存入到 action_queue、action_list、service_list中,解析过程可以看一下parse_config函数,类似状态机形式挺有意思。 这其中包含了服务:adbd、servicemanager、vold、ril-daemon、deb uggerd、surfaceflinger、zygote、media…… 2 服务启动 文件解析完成之后将service放入到service_list中。 文件解析完成之后将service放入到service_list中。 \system\core\init\builtins.c

相关主题
文本预览
相关文档 最新文档