Index: wp-includes/cron.php
===================================================================
--- wp-includes/cron.php	(revision 19704)
+++ wp-includes/cron.php	(working copy)
@@ -25,7 +25,6 @@
 	if ( $next && $next <= $timestamp + 600 )
 		return;
 
-	$crons = _get_cron_array();
 	$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => false, 'args' => $args );
 	$event = apply_filters('schedule_event', $event);
 
@@ -35,8 +34,8 @@
 
 	$key = md5(serialize($event->args));
 
+	$crons = _get_cron_array();
 	$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
-	uksort( $crons, "strnatcasecmp" );
 	_set_cron_array( $crons );
 }
 
@@ -61,7 +60,6 @@
  * @return bool|null False on failure, null when complete with scheduling event.
  */
 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
-	$crons = _get_cron_array();
 	$schedules = wp_get_schedules();
 
 	if ( !isset( $schedules[$recurrence] ) )
@@ -76,8 +74,8 @@
 
 	$key = md5(serialize($event->args));
 
+	$crons = _get_cron_array();
 	$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
-	uksort( $crons, "strnatcasecmp" );
 	_set_cron_array( $crons );
 }
 
@@ -93,17 +91,21 @@
  * @return bool|null False on failure. Null when event is rescheduled.
  */
 function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array()) {
-	$crons = _get_cron_array();
-	$schedules = wp_get_schedules();
-	$key = md5(serialize($args));
 	$interval = 0;
 
 	// First we try to get it from the schedule
-	if ( 0 == $interval )
+	$schedules = wp_get_schedules();
+	if ( !empty( $schedules ) )
 		$interval = $schedules[$recurrence]['interval'];
+
 	// Now we try to get it from the saved interval in case the schedule disappears
-	if ( 0 == $interval )
-		$interval = $crons[$timestamp][$hook][$key]['interval'];
+	if ( 0 == $interval ) {
+		$crons = _get_cron_array();
+		if ( !empty( $crons ) ) {
+			$key = md5( serialize( $args ) );
+			$interval = $crons[$timestamp][$hook][$key]['interval'];
+		}
+	}
 	// Now we assume something is wrong and fail to schedule
 	if ( 0 == $interval )
 		return false;
@@ -135,13 +137,13 @@
  */
 function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
 	$crons = _get_cron_array();
+	if ( empty( $crons ) )
+		return;
 	$key = md5(serialize($args));
 	unset( $crons[$timestamp][$hook][$key] );
 	if ( empty($crons[$timestamp][$hook]) )
 		unset( $crons[$timestamp][$hook] );
-	if ( empty($crons[$timestamp]) )
-		unset( $crons[$timestamp] );
-	_set_cron_array( $crons );
+	_set_cron_array( $crons, 'removed' );
 }
 
 /**
@@ -164,6 +166,27 @@
 		wp_unschedule_event( $timestamp, $hook, $args );
 }
 
+/** 
+* Unschedule all previously scheduled cron job for a hook. 
+*
+* Can be usefull for plugins when deactivating to clean up the cron queue 
+* 
+* The $hook parameter is required, so that the events can be 
+* identified. 
+* 
+* @since 3.4 
+* 
+* @param string $hook Action hook, the execution of which will be unscheduled. 
+*/ 
+function wp_unschedule_hook( $hook ) {
+	$crons = _get_cron_array();
+	if ( empty( $crons ) )
+		return;
+	foreach($crons as $timestamp => $args)
+		unset( $crons[$timestamp][$hook] );
+	_set_cron_array( $crons, 'removed' );
+}
+
 /**
  * Retrieve the next timestamp for a cron event.
  *
@@ -175,9 +198,9 @@
  */
 function wp_next_scheduled( $hook, $args = array() ) {
 	$crons = _get_cron_array();
+	if ( empty( $crons ) )
+		return false;
 	$key = md5(serialize($args));
-	if ( empty($crons) )
-		return false;
 	foreach ( $crons as $timestamp => $cron ) {
 		if ( isset( $cron[$hook][$key] ) )
 			return $timestamp;
@@ -373,8 +396,13 @@
  * @access private
  *
  * @param array $cron Cron info array from {@link _get_cron_array()}.
+ * @param string $action Default value 'added'. Other possible values : 'removed'.
  */
-function _set_cron_array($cron) {
+function _set_cron_array($cron, $action = 'added') {
+	if ('added' == $action)
+		uksort( $crons, "strnatcasecmp" );
+	if ('removed' == $action)
+		$crons = array_filter( $crons );
 	$cron['version'] = 2;
 	update_option( 'cron', $cron );
 }
