Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.577
diff -u -r1.577 common.inc
--- includes/common.inc	3 Oct 2006 00:24:19 -0000	1.577
+++ includes/common.inc	5 Oct 2006 00:43:34 -0000
@@ -1693,15 +1693,20 @@
  * Returns TRUE if ran successfully
  */
 function drupal_cron_run() {
+  $cron_run_time = variable_get('cron_run_time', 240);
+  $advanced_cron = variable_get('cron_run_advanced', FALSE);
+  $cron_info = array();
+
   // If not in 'safe mode', increase the maximum execution time:
+
   if (!ini_get('safe_mode')) {
-    set_time_limit(240);
+    set_time_limit($cron_run_time);
   }
 
   // Fetch the cron semaphore
   $semaphore = variable_get('cron_semaphore', FALSE);
 
-  if ($semaphore) {
+  if ($semaphore && !$_REQUEST['rid']) {
     if (time() - $semaphore > 3600) {
       // Either cron has been running for more than an hour or the semaphore
       // was not reset due to a database error.
@@ -1715,19 +1720,93 @@
       watchdog('cron', t('Attempting to re-run cron while it is already running.'), WATCHDOG_WARNING);
     }
   }
+  else if($_REQUEST['rid']) {
+    $rid = $_REQUEST['rid'];
+    $riid = $_REQUEST['riid'];
+    db_query("UPDATE {cron_run_info} SET run_date = " . time() . " WHERE riid = %d", $riid);
+    // Run this cron
+    module_invoke($_REQUEST['module'], 'cron');
+    # End Run
+    db_query("UPDATE {cron_run_info} SET run_status = %d, run_stop = %d WHERE riid = %d", WATCHDOG_NOTICE, time(), $riid);
+    db_query("UPDATE {cron_runs} SET run_ticks = run_ticks + 1 WHERE rid = %d", $rid);
+  }
   else {
+    # First truncate any old crons
+    $max_crons = variable_get('cron_run_history', 50);
+    $truncate = db_result(db_query("SELECT COUNT(*) FROM {cron_runs}"));
+    if($truncate) {
+      $rs = db_query_range("SELECT rid FROM {cron_runs} ORDER BY rid DESC", $max_crons, $truncate);
+      while($row = db_fetch_object($rs)) {
+        db_query("DELETE FROM {cron_run_info} WHERE rid = %d", $row->rid);
+        db_query("DELETE FROM {cron_runs} WHERE rid = %d", $row->rid);
+      }
+    }
+
+    if($advanced_cron) {
+      # Before we start again, if were in advanced mode, we need to see if we need to
+      # time out or error and cron runs.
+      # Since we're dealing with dates, and need a date diff, much easier to work
+      # with just a unix time stamp to do a simple (-)
+      db_query("UPDATE {cron_runs} SET run_status = '%d' WHERE (run_date - run_stop >= $cron_run_time) || (run_date - %d >= $cron_run_time)",
+        WATCHDOG_ERROR, time());
+      db_query("UPDATE {cron_run_info} SET run_status = '%d' WHERE (run_date - run_stop >= $cron_run_time) || (run_date - %d >= $cron_run_time)",
+        WATCHDOG_ERROR, time());
+    }
+
     // Register shutdown callback
     register_shutdown_function('drupal_cron_cleanup');
 
     // Lock cron semaphore
-    variable_set('cron_semaphore', time());
-
-    // Iterate through the modules calling their cron handlers (if any):
-    module_invoke_all('cron');
-
+    $semaphore = time();
+    variable_set('cron_semaphore', $semaphore);
+    if($advanced_cron) {
+      global $base_url;
+      db_query("INSERT INTO {cron_runs}(run_date, run_status) VALUES(%d, %d)", time(), WATCHDOG_WARNING);
+      $rid = db_result(db_query("SELECT MAX(rid) FROM {cron_runs}"));
+      $cmd = variable_get('cron_run_command', '');
+      if($cmd == '') {
+        exit();
+      }
+      # Start firing the modules
+      $modules = module_list(); 
+      $winos = eregi("windows",strtolower(php_uname()));
+      $module_count = 0;
+      foreach($modules as $module) {
+        if(module_hook($module, 'cron')) {
+          db_query("INSERT INTO {cron_run_info}(rid, module_name, run_status) VALUES(%d, '%s', %d)", $rid, $module, WATCHDOG_WARNING);
+          $riid = db_result(db_query("SELECT MAX(riid) FROM {cron_run_info}"));
+          
+          $run_cmd = "$cmd \"$base_url/cron.php?rid=$rid&riid=$riid&module=$module\""; 
+          if(!$winos) {
+            pclose(popen("$run_cmd & ", "r"));
+          }
+          else {
+            pclose(popen("start \"bla\" " . $run_cmd . " ", "r"));
+          }
+          $module_count++;
+        }
+      }
+      db_query("UPDATE {cron_runs} SET run_status = %d, run_stop = %d, run_ticks = %d", WATCHDOG_OK, time(), (-1 * $module_count));
+    }
+    else {
+      // Iterate through the modules calling their cron handlers (if any):
+      db_query("INSERT INTO {cron_runs}(run_date, run_status) VALUES(%d, %d)", time(), WATCHDOG_WARNING);
+      $rid = db_result(db_query("SELECT MAX(rid) FROM {cron_runs}"));
+      db_query("INSERT INTO {cron_run_info}(rid, module_name, run_status, run_date) VALUES(%d, '%s', %d, %d)", $rid, 'system-all-modules', WATCHDOG_WARNING, time());
+      $riid = db_result(db_query("SELECT MAX(riid) FROM {cron_run_info}"));
+      module_invoke_all('cron');
+      db_query("UPDATE {cron_run_info} SET run_status = %d, run_stop = %d WHERE riid = %d", WATCHDOG_NOTICE, time(), $riid);
+      db_query("UPDATE {cron_runs} SET run_status = %d, run_ticks = %d, run_stop = %d WHERE rid = %d",WATCHDOG_OK, 0, time(), $rid);
+    }
+    
     // Record cron time
     variable_set('cron_last', time());
-    watchdog('cron', t('Cron run completed.'), WATCHDOG_NOTICE);
+    if($advanced_cron) {
+      watchdog('cron', t('Cron run started <em>%module_count</em> runs.', array('%module_count' => $module_count)), WATCHDOG_NOTICE);
+    }
+    else {
+      watchdog('cron', t('Cron run completed.'), WATCHDOG_NOTICE);
+    }
 
     // Release cron semaphore
     variable_del('cron_semaphore');
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.372
diff -u -r1.372 system.module
--- modules/system/system.module	2 Oct 2006 16:49:08 -0000	1.372
+++ modules/system/system.module	5 Oct 2006 00:43:35 -0000
@@ -185,6 +185,7 @@
       }
     }
 
+    
     // Modules:
     $items[] = array('path' => 'admin/settings/modules',
       'title' => t('modules'),
@@ -194,6 +195,20 @@
       'callback arguments' => array('system_modules'),
       'access' => $access);
 
+    // Cron:
+    $items[] = array('path' => 'admin/settings/cron',
+      'title' => t('cron'),
+      'description' => t('Cron Settings'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('system_cron_settings'),
+      'access' => $access);
+    $items[] = array('path' => 'admin/logs/cron',
+      'title' => t('cron runs'),
+      'description' => t('Information about past cron runs'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('system_cron_logs'),
+      'access' => $access);
+
     // Settings:
     $items[] = array(
       'path' => 'admin/settings/site-information',
@@ -1219,6 +1234,155 @@
   return 'admin/build/themes';
 }
 
+ /**
+  * Cron logs
+  */
+function system_cron_logs($form_values = NULL) {
+  if(is_numeric(arg(3))) {
+    $rid = arg(3);
+    $cron_run = db_fetch_object(db_query("SELECT cr.rid, cr.run_date, cr.run_status, cr.run_ticks, cr.run_stop, COUNT(riid) modules_ran 
+      FROM {cron_runs} cr INNER JOIN {cron_run_info} ci ON cr.rid = ci.rid 
+      WHERE cr.rid = %d 
+      GROUP BY cr.rid, cr.run_date, cr.run_status, cr.run_ticks, cr.run_stop 
+      ", $rid));
+    if(!$cron_run) {
+      drupal_set_message(t('Invalid cron run given'), 'error');
+      drupal_goto('admin/logs/cron');
+    }
+
+    # Icon Setup
+    $icons = array(WATCHDOG_NOTICE  => theme('image', 'misc/watchdog-ok.png', t('ok'), t('ok')),
+                 WATCHDOG_WARNING => theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning')),
+                 WATCHDOG_ERROR   => theme('image', 'misc/watchdog-error.png', t('error'), t('error')));
+
+    # General Run Information
+    $form['cron_run_info'] = array('#value' => "
+      Run ID: <strong>$rid</strong><br/>
+      Run Date: <strong>" . format_date($cron_run->run_date, 'large') . "</strong><br/>
+      Modules Ran: <strong>$cron_run->modules_ran</strong><br/>
+      Run Status: " . $icons[$cron_run->run_status] . "<br/><hr/>
+    ");
+    
+    # Get the modules that ran
+    $module_runs = db_query("SELECT * FROM {cron_run_info} WHERE rid = %d", $rid);
+    $rows = $module_run = $row = $headers = array();
+    $time_format = 'h:i:s a';
+    while($module_run = db_fetch_object($module_runs)) {
+      $row = array();
+      $row[] = $module_run->module_name;
+      $row[] = format_date($module_run->run_date, 'custom', $time_format);
+      $row[] = format_date($module_run->run_stop, 'custom', $time_format);
+      if($module_run->run_stop) {
+        $row[] = ($module_run->run_stop - $module_run->run_date) . " seconds";
+      }
+      else {
+        $row[] = (time() - $module_run->run_date) . " seconds";
+      }
+      $row[] = $icons[$module_run->run_status];
+      $rows[] = $row;
+    }
+    $headers = array(t('Module'), t('Start'), t('Finish'), t('Run time'), t('Status'));
+    $form['run_table'] = array('#value' => 
+      theme('table', $headers, $rows));
+    
+  }
+  else {
+    $rs = pager_query ("SELECT * FROM {cron_runs}", 20);
+    while($row = db_fetch_object($rs)) {
+      $cron_runs[$row->rid] = $row;
+    }
+
+    $form['cron_runs'] = array('#value' => $cron_runs);
+    $form['pager_info'] = array('#value' => theme('pager', 20, NULL, 0));
+    $form['#theme'] = 'system_cron_runs_logs';
+  }
+   
+  return $form;
+  
+}
+
+function theme_system_cron_runs_logs($form) {
+
+  $icons = array(WATCHDOG_NOTICE  => theme('image', 'misc/watchdog-ok.png', t('ok'), t('ok')),
+                 WATCHDOG_WARNING => theme('image', 'misc/watchdog-warning.png', t('warning'), t('warning')),
+                 WATCHDOG_ERROR   => theme('image', 'misc/watchdog-error.png', t('error'), t('error')));
+  $headers = array(
+    array('field' => 'run_date', 'data' => t('Cron run date')),
+    array('field' => 'rid', 'data' => t('Run ID')),
+    array('field' => 'run_information', 'data' => t('Run status'))
+    );
+  $cron_runs = $form['cron_runs']['#value'];
+  unset($form['cron_runs']);
+  $row = $rows = array();
+  foreach($cron_runs as $rid => $info) {
+    $link = 'admin/logs/cron/' . $rid;
+    $row['data'] = array(l(format_date($info->run_date,'long'), $link), l($rid, $link), $icons[$info->run_status]);
+    $row['class'] = 'ok';
+    $row['align'] = 'center';
+    $rows[] = $row;
+    $row = array();
+  }
+  
+  $output .= drupal_render($form);
+  $output .= theme('table', $headers, $rows, array('class' => 'system-status-report'));
+  return $output;
+ 
+}
+
+
+/**
+ * Menu callback; provides the cron basic/advanced settings interface.
+ *
+ * A cron run can be setup to run in a "multi-threaded" enviroment.
+ * Each module will have it's own "report" of how it ran, etc.
+ *
+ * @return
+ *   The form array.
+ */
+function system_cron_settings($form_values = NULL) {
+  global $base_url;
+  $form['basic_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Basic Cron Settings'),
+    '#collapsible' => FALSE);
+  $form['basic_settings']['cron_run_time'] = array(
+    '#type' => 'textfield',
+    '#size' => 5,
+    '#title' => t('Cron run time'),
+    '#description' => t('This is the time in seconds that a cron run is alloted to complete a run. Try increasing this value if you notice that 
+      you have a lot of errors of your cron run not finishing.'),
+    '#default_value' => variable_get('cron_run_time', 240));
+  $history_options = drupal_map_assoc(range(50,1000,50));
+  $form['basic_settings']['cron_run_history'] = array(
+    '#type' => 'select',
+    '#title' => t('Cron history'),
+    '#options' => $history_options,
+    '#default_value' => variable_get('cron_run_history', 50),
+    '#description' => t('The number of cron runs you would like to keep. It will delete starting with the oldest cron run.'));
+  if($base_url == '') {
+    drupal_set_message('warning', t('In order to use advanced cron settings, you must set the $base_url variable in your settings.php file.'));
+  } else {
+    $form['advanced_cron_settings'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Advanced Cron Settings'),
+      '#collapsible' => FALSE);
+    $form['advanced_cron_settings']['cron_run_advanced'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable advanced cron runs'),
+      '#description' => t('Check this box to have your cron runs run in a multi-threaded enviroment. 
+        This will also give you more information about each individual modules cron run.'),
+      '#default_value' => variable_get('cron_run_advanced', FALSE));
+    $form['advanced_cron_settings']['cron_run_command'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Cron run command'),
+      '#description' => t('This is the command you use to run your cron. Use <em>ONLY</em> the command. Example: <strong><em>/usr/bin/lynx -source</em></strong>'),
+      '#default_value' => variable_get('cron_run_command', ""));
+  }
+
+  
+  return system_settings_form($form);
+}
+
 /**
  * Menu callback; provides module enable/disable interface.
  *
@@ -1541,7 +1705,12 @@
 function system_run_cron() {
    // Run cron manually
    if (drupal_cron_run()) {
-     drupal_set_message(t('Cron ran successfully'));
+     if(variable_get('cron_run_advanced', FALSE)) {
+       drupal_set_message(t('Cron started successfull'));
+     }
+     else {
+      drupal_set_message(t('Cron ran successfully'));
+     }
    }
    else {
      drupal_set_message(t('Cron run failed'));
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.30
diff -u -r1.30 system.install
--- modules/system/system.install	2 Oct 2006 11:31:35 -0000	1.30
+++ modules/system/system.install	5 Oct 2006 00:43:36 -0000
@@ -160,6 +160,25 @@
         UNIQUE KEY info (info)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
+      db_query("CREATE TABLE {cron_runs} (
+        rid int(11) NOT NULL auto_increment,
+        run_date varchar(20),
+        run_stop varchar(20),
+        run_ticks int(11),
+        run_status char(1),
+        PRIMARY KEY(rid)
+      ) /*!40100 DEFAULT CHRACTER SET UTF8 */");
+
+      db_query("CREATE TABLE {cron_run_info} (
+        riid int(11) NOT NULL auto_increment,
+        rid int(11) NOT NULL,
+        module_name varchar(50),
+        run_date varchar(20),
+        run_stop varchar(20),
+        run_status char(1),
+        PRIAMRY KEY(riid)
+      ) /*!40100 DEFAULT CHRACTER SET UTF8 */");
+
       db_query("CREATE TABLE {cache} (
         cid varchar(255) NOT NULL default '',
         data longblob,

