Author: mhabersack
Date: 2007-08-09 04:20:02 -0400 (Thu, 09 Aug 2007)
New Revision: 83716

Modified:
   trunk/mod_mono/ChangeLog
   trunk/mod_mono/src/mod_mono.c
Log:
2007-08-08  Joshua Tauberer  <[EMAIL PROTECTED]>

        * src/mod_mono.c: some fixes for the cross-process
        locking and refactored process limits.
        - Added a flag in the dashboard to ensure only one child process
        issues an automated restart request to xsp.
        - Don't assume the mutex is actually ever created in case of problems.
        - Don't call apr_global_mutex_child_init if MOD_MONO_LOCKING_MECHANISM
        is set, since for me this causes all locks to block forever.
        - Improved some error messages and added one about command stream
        corruption.
        - When the auto-restart check cannot get a lock, don't return a
        HTTP_SERVICE_UNAVAILABLE status code, since we've already successfully
        sent page output.
        - Don't reset the dashboard in start_xsp if no fork was necessary.
        - Included dashboard info in the control panel.
        - Refactored process limits in order to aid debugging on why it
        doesn't work at all.


Modified: trunk/mod_mono/ChangeLog
===================================================================
--- trunk/mod_mono/ChangeLog    2007-08-09 08:05:54 UTC (rev 83715)
+++ trunk/mod_mono/ChangeLog    2007-08-09 08:20:02 UTC (rev 83716)
@@ -1,3 +1,22 @@
+2007-08-08  Joshua Tauberer  <[EMAIL PROTECTED]>
+
+       * src/mod_mono.c: some fixes for the cross-process
+       locking and refactored process limits.
+       - Added a flag in the dashboard to ensure only one child process
+       issues an automated restart request to xsp.
+       - Don't assume the mutex is actually ever created in case of problems.
+       - Don't call apr_global_mutex_child_init if MOD_MONO_LOCKING_MECHANISM
+       is set, since for me this causes all locks to block forever.
+       - Improved some error messages and added one about command stream
+       corruption.
+       - When the auto-restart check cannot get a lock, don't return a
+       HTTP_SERVICE_UNAVAILABLE status code, since we've already successfully
+       sent page output.
+       - Don't reset the dashboard in start_xsp if no fork was necessary.
+       - Included dashboard info in the control panel.
+       - Refactored process limits in order to aid debugging on why it
+       doesn't work at all.
+
 2007-08-06  Marek Habersack  <[EMAIL PROTECTED]>
 
        * configure.in: added --enable-gcov option to enable gcov(1)

Modified: trunk/mod_mono/src/mod_mono.c
===================================================================
--- trunk/mod_mono/src/mod_mono.c       2007-08-09 08:05:54 UTC (rev 83715)
+++ trunk/mod_mono/src/mod_mono.c       2007-08-09 08:20:02 UTC (rev 83716)
@@ -62,6 +62,7 @@
 typedef struct {
        uint32_t handled_requests;
        time_t start_time;
+       char restart_issued;
 } dashboard_data;
 
 typedef struct xsp_data {
@@ -392,6 +393,7 @@
                                xsp->dashboard = apr_shm_baseaddr_get 
(xsp->dashboard_shm);
                                xsp->dashboard->start_time = time (NULL);
                                xsp->dashboard->handled_requests = 0;
+                               xsp->dashboard->restart_issued = 0;
                                goto restore_creds;
                        }
                }
@@ -472,7 +474,7 @@
        server->restart_mode = AUTORESTART_MODE_INVALID;
        server->restart_requests = 0;
        server->restart_time = 0;
-  
+
        ensure_dashboard_initialized (config, server, pool);
        
        nservers = config->nservers + 1;
@@ -1362,27 +1364,39 @@
 }
 
 static void
-set_process_limits (int max_cpu_time, int max_memory)
-{
-#ifdef HAVE_SETRLIMIT
+set_process_limits2 (int resource, int max, char *name) {
        struct rlimit limit;
 
-       if (max_cpu_time > 0) {
+       if (max > 0) {
+#ifdef HAVE_SETRLIMIT
                /* We don't want SIGXCPU */
-               limit.rlim_cur = max_cpu_time;
-               limit.rlim_max = max_cpu_time;
-               DEBUG_PRINT (1, "Setting CPU time limit to %d", max_cpu_time);
-               (void) setrlimit (RLIMIT_CPU, &limit);
+               limit.rlim_cur = max;
+               limit.rlim_max = max;
+               DEBUG_PRINT (1, "Setting %s limit to %d", name, max);
+               if (setrlimit (resource, &limit) == -1) {
+                       if (errno == EPERM)
+                               ap_log_error (APLOG_MARK, APLOG_ERR, 
STATUS_AND_SERVER,
+                                             "Failed to set %s process limit 
on mod-mono-server to %d: The value is greater than an existing hard limit", 
name, max);
+                       else
+                               ap_log_error (APLOG_MARK, APLOG_ERR, 
STATUS_AND_SERVER,
+                                             "Failed to set %s process limit 
on mod-mono-server to %d.", name, max);
+               }
+#else
+               ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER,
+                             "Setting %s process limit is not supported on 
this platform.", name);
+#endif
        }
+}
 
-       if (max_memory > 0) {
-               /* We don't want ENOMEM */
-               limit.rlim_cur = max_memory;
-               limit.rlim_max = max_memory;
-               DEBUG_PRINT (1, "Setting memory limit to %d", max_memory);
-               (void) setrlimit (RLIMIT_DATA, &limit);
-       }
+static void
+set_process_limits (int max_cpu_time, int max_memory)
+{
+#ifndef HAVE_SETRLIMIT
+#define RLIMIT_CPU 0
+#define RLIMIT_DATA 0
 #endif
+       set_process_limits2 (RLIMIT_CPU, max_cpu_time, "CPU time");
+       set_process_limits2 (RLIMIT_DATA, max_memory, "memory (data segment)");
 }
 
 static void
@@ -1813,7 +1827,7 @@
 {
        apr_socket_t *sock;
        apr_status_t rv;
-       int command;
+       int command = -1;
        int result = FALSE;
        apr_status_t input;
        int status = 0;
@@ -1866,8 +1880,20 @@
        if (start_wait_time < 2)
                start_wait_time = 2;
 
-       if (!conf->dashboard_mutex_initialized_in_child) {
-               rv = apr_global_mutex_child_init (&conf->dashboard_mutex, 
conf->dashboard_lock_file, pconf);
+       ensure_dashboard_initialized (config, conf, pconf);
+       if (conf->dashboard_mutex && 
!conf->dashboard_mutex_initialized_in_child) {
+               /* Avoiding to call apr_global_mutex_child_init is a hack since 
in certain
+                * conditions it may lead to apache deadlock. Since we don't 
know the exact cause
+                * and usually it is not necessary to use the environment 
variable to work around
+                * the apr's default locking mechanism, we skip the call in 
case the envvar is
+                * used.
+                */
+               if (!getenv ("MOD_MONO_LOCKING_MECHANISM")) {
+                       rv = apr_global_mutex_child_init 
(&conf->dashboard_mutex, conf->dashboard_lock_file, pconf);
+               } else {
+                       DEBUG_PRINT (0, "Skipping apr_global_mutex_child_init 
on '%s'", conf->dashboard_lock_file);
+                       rv = APR_SUCCESS;
+               }
                if (rv != APR_SUCCESS) {
                        ap_log_error (APLOG_MARK, APLOG_CRIT, 
STATCODE_AND_SERVER (rv),
                                      "Failed to initialize the dashboard mutex 
'%s' in child process",
@@ -1885,8 +1911,11 @@
                                return HTTP_SERVICE_UNAVAILABLE;
                        DEBUG_PRINT (2, "No backend found, will start a new 
copy.");
 
-                       rv = apr_global_mutex_lock (conf->dashboard_mutex);
-                       DEBUG_PRINT (1, "Acquired the %s lock for backend 
start", conf->dashboard_lock_file);
+                       if (conf->dashboard_mutex)
+                               rv = apr_global_mutex_lock 
(conf->dashboard_mutex);
+                       else
+                               rv = APR_SUCCESS;
+                       DEBUG_PRINT (1, "Acquiring the %s lock for backend 
start", conf->dashboard_lock_file);
       
                        if (rv != APR_SUCCESS) {
                                ap_log_error (APLOG_MARK, APLOG_CRIT, 
STATCODE_AND_SERVER (rv),
@@ -1903,11 +1932,13 @@
                        /* give some time for warm-up */
                        DEBUG_PRINT (2, "Started new backend, sleeping %us to 
let it configure", (unsigned)start_wait_time);
                        apr_sleep (apr_time_from_sec (start_wait_time));
-                       rv = apr_global_mutex_unlock (conf->dashboard_mutex);
-                       if (rv != APR_SUCCESS)
-                               ap_log_error (APLOG_MARK, APLOG_ALERT, 
STATCODE_AND_SERVER (rv),
-                                             "Failed to release %s lock, the 
process may deadlock!",
-                                             conf->dashboard_lock_file);
+                       if (conf->dashboard_mutex) {
+                               rv = apr_global_mutex_unlock 
(conf->dashboard_mutex);
+                               if (rv != APR_SUCCESS)
+                                       ap_log_error (APLOG_MARK, APLOG_ALERT, 
STATCODE_AND_SERVER (rv),
+                                                     "Failed to release %s 
lock, the process may deadlock!",
+                                                     
conf->dashboard_lock_file);
+                       }
                } else
                        break; /* connected */
        }
@@ -1930,23 +1961,29 @@
        } while (input == sizeof (int32_t) && result == TRUE);
 
        apr_socket_close (sock);
-       if (input != sizeof (int32_t))
+       if (input != sizeof (int32_t)) {
+               ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER,
+                             "Command stream corrupted, last command was %d", 
command);
                status = HTTP_INTERNAL_SERVER_ERROR;
+       }
 
        if (conf->restart_mode > AUTORESTART_MODE_NONE) {
                int do_restart = 0;
                
                DEBUG_PRINT (2, "Auto-restart enabled for '%s', checking if 
restart required", conf->alias);
                
+               ensure_dashboard_initialized (config, conf, pconf);
+               if (!conf->dashboard_mutex)
+                       return status;
+
                rv = apr_global_mutex_lock (conf->dashboard_mutex);
                DEBUG_PRINT (1, "Acquired the %s lock for backend auto-restart 
check", conf->dashboard_lock_file);
-               ensure_dashboard_initialized (config, conf, pconf);
                
                if (rv != APR_SUCCESS) {
                        ap_log_error (APLOG_MARK, APLOG_CRIT, 
STATCODE_AND_SERVER (rv),
-                                     "Failed to acquire %s lock, cannot 
continue starting new process",
+                                     "Failed to acquire %s lock, cannot 
continue auto-restart check",
                                      conf->dashboard_lock_file);
-                       return HTTP_SERVICE_UNAVAILABLE;
+                       return status;
                }
 
                if (conf->restart_mode == AUTORESTART_MODE_REQUESTS) {
@@ -1970,17 +2007,21 @@
                        }
                }
 
-               if (do_restart) {
+               if (do_restart && !conf->dashboard->restart_issued) {
                        /* we just need to stop it, it will be started at the 
next request */
                        DEBUG_PRINT (0, "Stopping the backend '%s', it will be 
started at the next request",
                                     conf->alias);
+                       ap_log_error (APLOG_MARK, APLOG_ALERT, 
STATCODE_AND_SERVER (rv),
+                                     "Requesting termination of %s 
mod-mono-server for restart...",
+                                     conf->alias);
+                       conf->dashboard->restart_issued = 1;
                        terminate_xsp2 (r->server, conf->alias, 1);
                }
                
                rv = apr_global_mutex_unlock (conf->dashboard_mutex);
                if (rv != APR_SUCCESS)
                        ap_log_error (APLOG_MARK, APLOG_ALERT, 
STATCODE_AND_SERVER (rv),
-                                     "Failed to release %s lock, the process 
may deadlock!",
+                                     "Failed to release %s lock after 
auto-restart check, the process may deadlock!",
                                      conf->dashboard_lock_file);
        }
        
@@ -2100,7 +2141,7 @@
 
                if (!strcmp ("XXGLOBAL", xsp->alias) && config->auto_app == 
FALSE)
                        continue;
-               
+
 #ifdef APACHE13
                sock = apr_pcalloc (pconf, sizeof (apr_socket_t));
 #endif
@@ -2116,7 +2157,6 @@
                                i--;
                                continue; /* Wait for the previous to die */
                        }
-
                        apr_socket_close (sock);
                        xsp->status = FORK_SUCCEEDED;
                } else {
@@ -2124,14 +2164,14 @@
                        /* need fork */
                        xsp->status = FORK_INPROCESS;
                        DEBUG_PRINT (0, "forking %s", xsp->alias);
-                       /* Give some time for clean up */
                        fork_mod_mono_server (pconf, xsp);
                        xsp->status = FORK_SUCCEEDED;
+                       if (xsp->dashboard) {
+                               xsp->dashboard->start_time = time (NULL);
+                               xsp->dashboard->handled_requests = 0;
+                               xsp->dashboard->restart_issued = 0;
+                       }
                }
-               if (xsp->dashboard) {
-                       xsp->dashboard->start_time = time (NULL);
-                       xsp->dashboard->handled_requests = 0;
-               }
        }
 }
 
@@ -2216,6 +2256,7 @@
        xsp_data *xsp;
        int i;
        char *buffer;
+       apr_status_t rv;
 
        if (strcmp (r->handler, "mono-ctrl"))
                return DECLINED;
@@ -2241,8 +2282,32 @@
                                continue;
 
                        buffer = apr_psprintf (r->pool, "<li>%s: <a 
href=\"?restart=%s\">"
-                                              "Restart Server</a></li>\n", 
xsp->alias, xsp->alias);
+                                              "Restart Server</a>", 
xsp->alias, xsp->alias);
                        request_send_response_string(r, buffer);
+
+                       ensure_dashboard_initialized (config, xsp, pconf);
+                       if (xsp->dashboard_mutex) {
+                               rv = apr_global_mutex_lock 
(xsp->dashboard_mutex);
+                               if (rv == APR_SUCCESS) {
+                                       if (xsp->restart_mode == 
AUTORESTART_MODE_REQUESTS) {
+                                               buffer = apr_psprintf (r->pool, 
" [%d requests served; limit: %d]",
+                                                                      
xsp->dashboard->handled_requests, xsp->restart_requests);
+                                               request_send_response_string(r, 
buffer);
+                                       } else if (xsp->restart_mode == 
AUTORESTART_MODE_TIME) {
+                                               buffer = apr_psprintf (r->pool, 
" [%ds time running; limit: %ds]",
+                                                                      
(int)(time(NULL) - xsp->dashboard->start_time), (int)xsp->restart_time);
+                                               request_send_response_string(r, 
buffer);
+                                       }
+
+                                       rv = apr_global_mutex_unlock 
(xsp->dashboard_mutex);
+                                       if (rv != APR_SUCCESS)
+                                               ap_log_error (APLOG_MARK, 
APLOG_ALERT, STATCODE_AND_SERVER (rv),
+                                                             "Failed to 
release %s lock after mono-ctrl output, the process may deadlock!",
+                                                             
xsp->dashboard_lock_file);
+                               }
+                       }
+
+                       request_send_response_string(r, "</li>\n");
                }
                
                request_send_response_string (r, "</ul>\n");

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to