Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.676
diff -u -p -r1.676 system.module
--- modules/system/system.module	25 Mar 2009 18:40:50 -0000	1.676
+++ modules/system/system.module	28 Mar 2009 17:54:29 -0000
@@ -1597,6 +1597,8 @@ function system_cron() {
   foreach ($cache_tables as $table) {
     cache_clear_all(NULL, $table);
   }
+  // Work off scheduled tasks.
+  system_scheduler_work();
 }
 
 /**
@@ -2323,3 +2325,90 @@ function system_image_toolkits() {
     ),
   );
 }
+
+/**
+ * Job scheduler. Add a task as a function callback to the queue for processing 
+ * on cron time.
+ * 
+ * @see system_scheduler_remove().
+ * 
+ * @param $callback
+ *   Callback function to be invoked by scheduler.
+ * @param $arguments
+ *   Arguments to be passed to callback function.
+ * @param $minimum_period
+ *   Minimum time until $callback is executed. One of 
+ *   0 (as soon as possible)
+ *   300 (5 minutes)
+ *   1800 (30 minutes)
+ *   3600 (1 hour)
+ *   43200 (12 hours)
+ *   86400 (24 hours)
+ * @param $repeat
+ *   If TRUE, task will repeated within $minimum_period. If FALSE, task will
+ *   removed from queue after execution.
+ * @return 
+ *   A queue item if successful. It's the implementers responsibility to keep 
+ *   track of the items added to the scheduler - see system_scheduler_remove().
+ */
+function system_scheduler_add($callback, $arguments, $minimum_period = 0, $repeat = FALSE) {
+  if (!in_array($minimum_period, system_scheduler_get_schedules())) {
+    return FALSE;
+  }
+  $item = new stdClass();
+  $item->callback = $callback;
+  $item->arguments = $arguments;
+  $item->minimum_period = $minimum_period;
+  $item->repeat = $repeat;
+  // @todo: queue_add does not accept a process time ATM.
+  return queue_add('scheduler_' . $minimum_period, $item, $minimum_period);
+}
+
+/**
+ * Worker function for job scheduler.
+ */
+function system_scheduler_work() {
+  // Work for 50 % available max execution time, but not longer than max
+  // execution time itself. Assume a safety buffer of 30 seconds.
+  // @todo: this could be made adjustable.
+  $max_execution_time = ini_get('max_execution_time') - 30;
+  $time_out = time() + $max_execution_time / 2;
+  $time_out = $time_out > REQUEST_TIME + $max_execution_time ? REQUEST_TIME + $max_execution_time : $time_out;
+
+  // Work through all queues.
+  foreach (system_scheduler_get_schedules() as $time) {
+    while ($item = queue_reserve('scheduler_' . $time, $time)) {
+      if (drupal_function_exists($item->callback)) {
+        call_user_func($item->callback, $item->arguments);
+      }
+      if (!$item->repeat) {
+        queue_delete($item);
+      }
+      if (time() > $time_out) {
+        return;
+      }
+    }
+  }
+}
+
+/**
+ * Remove an item from the job scheduler.
+ * 
+ * @see system_scheduler_add()
+ * 
+ * @param $item
+ *   Item returned by system_scheduler_add().
+ */
+function system_scheduler_remove($item) {
+  foreach (system_scheduler_get_schedules() as $time) {
+    // @todo: function signature of queue_delete() unclear.
+    queue_delete('scheduler_'. $time, $item);
+  }
+}
+
+/**
+ * Return an array of available schedules.
+ */
+function system_scheduler_get_schedules() {
+  return array(0, 300, 1800, 3600, 43200, 86400);
+}
\ No newline at end of file
