/*
 * Given an element, remove it from the btree if it's already
 * there and re-insert it based on its current key.
 */
void
schedule_add_modify (struct schedule *s, struct schedule_entry *e)
{
#ifdef ENABLE_DEBUG
  if (check_debug_level (D_SCHEDULER))
    schedule_entry_debug_info ("schedule_add_modify", e);
#endif

  /* already in tree, remove */
  if (IN_TREE (e))
    schedule_remove_node (s, e);

  /* set random priority */
  schedule_set_pri (e);

  if (s->root)
    schedule_insert (s, e);      /* trivial insert into tree */
  else
    s->root = e; /* tree was empty, we are the first element */

  /* This is the magic of the randomized treap algorithm which
     keeps the tree balanced.  Move the node up the tree until
     its own priority is greater than that of its parent */
  while (e->parent && e->parent->pri > e->pri)
    schedule_rotate_up (s, e);
}
Exemple #2
0
/*************************************************************************
schedule_reschedule:
  Moves an item from one time to another in the schedule.  Currently, this is
  used when the unimolecular rates for a subunit cause a molecule's
  unimolecular reaction rate to change.

  In: struct schedule_helper *sh - the scheduler from which to remove
      void  *data - the item to remove
      double new_t - the new time for the item
  Out: 0 on success, 1 if the item was not found
*************************************************************************/
int schedule_reschedule(struct schedule_helper *sh, void *data, double new_t) {
  if (!schedule_deschedule(sh, data)) {
    struct abstract_element *ae = (struct abstract_element *)data;
    ae->t = new_t;
    return schedule_insert(sh, data, 1);
  } else
    return 1;
}
Exemple #3
0
int schedule_advance(struct schedule_helper *sh, struct abstract_element **head,
                     struct abstract_element **tail) {
  int n;
  struct abstract_element *p, *nextp;

  if (head != NULL)
    *head = sh->circ_buf_head[sh->index];
  if (tail != NULL)
    *tail = sh->circ_buf_tail[sh->index];

  sh->circ_buf_head[sh->index] = sh->circ_buf_tail[sh->index] = NULL;
  sh->count -= n = sh->circ_buf_count[sh->index];
  sh->circ_buf_count[sh->index] = 0;

  sh->index++;
  sh->now += sh->dt;

  if (sh->index >= sh->buf_len) {
    /* Move events from coarser time scale to this time scale */

    sh->index = 0;
    if (sh->next_scale != NULL) {
      /* Save our depth */
      int old_depth = sh->depth;
      int conservecount = sh->count;

      /* Hack: Toggle the non-zero-ness of our depth to toggle FIFO/LIFO
       * behavior
       */
      sh->depth = old_depth ? 0 : -1;

      if (schedule_advance(sh->next_scale, &p, NULL) == -1) {
        sh->depth = old_depth;
        return -1;
      }
      while (p != NULL) {
        nextp = p->next;
        if (schedule_insert(sh, (void *)p, 0)) {
          sh->depth = old_depth;
          return -1;
        }
        p = nextp;
      }

      /* moved items were already counted when originally scheduled so don't
       * count again */
      sh->count = conservecount;

      /* restore our depth */
      sh->depth = old_depth;
    }
  }

  return n;
}
Exemple #4
0
struct thread *thread_thaw(struct thread *thread) {
	
	if (thread->frozen) {
		thread->frozen--;
	}

	if (!thread->frozen) {
		schedule_insert(thread);
	}

	return thread;
}
Exemple #5
0
struct thread *thread_send(struct thread *image, pid_t target, portid_t port, struct msg *msg) {
	struct process *p_targ;
	struct thread *new_image;

	/* find target process */
	p_targ = process_get(target);

	/* check process */
	if (!p_targ || !p_targ->entry) {
		return image;
	}

	/* create new thread */
	new_image = thread_alloc();
	thread_bind(new_image, p_targ);

	new_image->ds      = 0x23;
	new_image->cs      = 0x1B;
	new_image->ss      = 0x23;
	new_image->eflags  = 0;
	new_image->useresp = new_image->stack + SEGSZ;
	new_image->proc    = p_targ;
	new_image->eip     = p_targ->entry;

	/* set up registers in new thread */
	new_image->ebx     = 0;
	new_image->ecx     = (msg) ? msg->count : 0;
	new_image->edx     = port;
	new_image->esi     = (image) ? image->proc->pid : 0;
	new_image->edi     = 0;
	new_image->msg     = msg;

	/* set new thread's user id */
	new_image->user = (!image || p_targ->user) ? p_targ->user : image->user;

	/* insert new thread into scheduler */
	schedule_insert(new_image);

	/* return new thread */
	return new_image;
}
Exemple #6
0
static void set_expire_event(timeval_t t) {
  disable_interrupts();
  expire_event.time = t;
  schedule_insert(current_time(), &expire_event);
  enable_interrupts();
}
void inline radio_state() {
	if (init) {
		schedule_insert(system_schedule, 0, ms_clock, get_time);
		schedule_insert(system_schedule, 0, ms_clock, get_rbds);
		schedule_insert(system_schedule, 0, ms_clock, get_status);
		schedule_insert(system_schedule, 0, ms_clock, display_radio_screen);
		schedule_insert(system_schedule, 0, ms_clock, display_radio_channel);
		schedule_insert(system_schedule, 0, ms_clock, display_rbds_information);
		schedule_insert(system_schedule, 0, ms_clock, start_ADC_conversion);
		
		if (!radio_is_on) {		
			si4705_power_on();
			si4705_set_channel(channel);
			set_volume(ADC_values[0]);
		}
		radio_is_on = true;
		what_the_beep = false;
		nokia5110_clear();
		wd_clock = 0; //second counter
		#ifndef USING_PRINTF
		PORTD &= ~_BV(0); // Turn the radio LED on
		PORTD |= _BV(1); // Turn the stereo status LED off
		#endif
	}
	if(bns[0]) {
		bns[0] = false;
		if (radio_activity == 1) {
			channel -= 2;
			if (channel%2 == 0) {
				channel += 1;
			}
			if (channel < SI4705_FM_LOW) channel = SI4705_FM_HIGH;
			si4705_set_channel(channel);
			clear_radio_strings();
		}
		radio_activity = 1;
		wd_clock = 0; //reset activity
		schedule_insert(system_schedule, 200, ms_clock, button_down);
	}
	if(bns[1]) {
		bns[1] = false;
		eeprom_update_word(&saved_channel, channel);
		state = menu;
	}
	if(bns[2]) {
		//printf("I was pressed up\n");
		bns[2] = false;
		if (radio_activity == 2) {
			channel += 2;
			if (channel%2 == 0) {
				channel -= 1;
			}
			if (channel < SI4705_FM_LOW) channel = SI4705_FM_HIGH;
			si4705_set_channel(channel);
			clear_radio_strings();
		}
		radio_activity = 2;
		wd_clock = 0; //reset activity
		////printf("event scheduled\n");
		schedule_insert(system_schedule, 200, ms_clock, button_up);
	}
	if (event_is_ready) {
		switch(next_event.id) {
			case start_ADC_conversion:
				ADC_start_conversion();
				set_brightness(photo_avg/PHOTO_AVG_RESOLUTION);
				set_volume(ADC_values[0]);
				schedule_insert(system_schedule, 20, ms_clock, start_ADC_conversion);
				break;
			
			case get_time:
				ds1307_getdate_s(&time);
				schedule_insert(system_schedule, 1000, ms_clock, get_time);
				//printf("%d:%d:%d\n", time.hour, time.minute, time.second);
				break;
			
			case get_rbds:
				si4705_get_rdbs(station_text, scroll_text);
				schedule_insert(system_schedule, 200, ms_clock, get_rbds);
				break;
			
			case get_status:
				si4705_get_tune_status(&radio_tune_status);
				si4705_get_rsq_status(&radio_rsq_status);
				channel = radio_tune_status.tuneFrequency;
				//printf("%u\n", channel);
				schedule_insert(system_schedule, 100, ms_clock, get_status);
				break;
			
			case display_radio_screen:
				nokia5110_gotoXY(14,0);
				snprintf(line, 10, "%02d:%02d %s", time.hour - 12*(time.hour>12), time.minute, time.hour<12?"am":"pm");
				nokia5110_writeString(line);
				
				schedule_insert(system_schedule, 1000, ms_clock, display_radio_screen);
				break;
			
			case display_radio_channel:
				nokia5110_gotoXY(8-8*(channel>=1000),1);
				snprintf(line, 8, " %d.%d ", channel/10, channel%10);
				nokia5110_writeString_megaFont(line);
				
				nokia5110_gotoXY(0, 2);
				snprintf(line, 2, "%c", 124+(ADC_values[0]>80)+(ADC_values[0]>180));
				nokia5110_writeString(line);
				
				nokia5110_gotoXY(0, 3);
				snprintf(line, 2, "%c", 128 + (radio_rsq_status.rssi>22) + (radio_rsq_status.rssi>35));
				nokia5110_writeString(line);
				
				nokia5110_gotoXY(70, 3);
				snprintf(line, 3, "%s", radio_rsq_status.pilot?"st":"  ");
				nokia5110_writeString(line);
				
				#ifndef USING_PRINTF
				if (radio_rsq_status.pilot) {
					PORTD &= ~(_BV(1)); // Turn the stereo status on
				} else {
					PORTD |= _BV(1); // Turn the stereo status off
				}
				#endif
				
				schedule_insert(system_schedule, 100, ms_clock, display_radio_channel);
				break;
			
			case display_rbds_information:
				rbds_pixel_offset = (rbds_pixel_offset+1) % 7;
				if (rbds_pixel_offset == 0) {
					text_index = (text_index + 1) % (strlen(scroll_text));
				}
				if (strlen(scroll_text) > DISPLAY_OFFSET+1) { // we have a radio string
					nokia5110_gotoXY(0,5);
					nokia5110_writeString_L(&scroll_text[text_index], rbds_pixel_offset);
					//nokia5110_writeString_C(&scroll_text[text_index]);
				} else if (strlen(station_text) > 0) { // we don't have a radio string, but we have program service!
					snprintf(line, 12, "%s            ", station_text);
					nokia5110_gotoXY(14,5);
					nokia5110_writeString_C(line);
				} else { // we got nothing
					nokia5110_gotoXY(0,5);
					nokia5110_writeString("            ");
				}
				
				schedule_insert(system_schedule, 100, ms_clock, display_rbds_information);
				break;
			
			case button_down:
				if (hol[0]) {
					si4705_seek(DOWN);
					clear_radio_strings();
				} else {
					channel -= 2;
					if (channel%2 == 0) {
						channel += 1;
					}
					if (channel < SI4705_FM_LOW) channel = SI4705_FM_HIGH;
					si4705_set_channel(channel);
					clear_radio_strings();
				}
				radio_activity = 0;
				break;
			
			case button_up:
				//printf("handling event - ");
				if (hol[2]) {
					//printf("you were holding\n");
					si4705_seek(UP);
					clear_radio_strings();
				} else {
					//printf("you were tapping\n");
					channel += 2;
					if (channel%2 == 0) {
						channel -= 1;
					}
					if (channel > SI4705_FM_HIGH) channel = SI4705_FM_LOW;
					si4705_set_channel(channel);
					clear_radio_strings();
				}
				radio_activity = 0;
				break;
			
			default:
				break;
		}
	}
	
	if (wd_clock == 3599) {
		state = last_state;
	}
}
void inline preset_state() {
	if (init) {
		schedule_insert(system_schedule, 0, ms_clock, start_ADC_conversion);
		
		menu_index = 0;
		nokia5110_clear();
		
		for (err = 0; err < NUMBER_OF_PRESETS; err++) {
			nokia5110_gotoXY(0, err);
			snprintf(line, 12, " %u.%u", presets[err]/10, presets[err]%10);
			nokia5110_writeString(line);
		}
		nokia5110_gotoXY(0,0);
		nokia5110_writeString(">");
		nokia5110_gotoXY(0,5);
		nokia5110_writeString(" Back");
	}
	if (bns[0]) {
		bns[0] = false;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(" ");
		menu_index = (menu_index+1) % 6;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(">");
		wd_clock = 0; // reset activity
		watchdog_feed();
	}
	if (bns[1]) {
		bns[1] = false;
		if(menu_index == 5) {
			state = last_state;
		} else {
			// choose preset
			if (last_state == home) {
				nokia5110_gotoXY(0,menu_index);
				nokia5110_writeString(" ");
				err = set_preset_variable(menu_index);
				if (err) {
					state = last_state;
				}
				nokia5110_gotoXY(0,menu_index);
				snprintf(line, 12, ">%u.%u", presets[menu_index]/10, presets[menu_index]%10);
				nokia5110_writeString(line);
			} else {	
				if (channel != presets[menu_index]) {
					channel = presets[menu_index];
					si4705_set_channel(channel);
					clear_radio_strings();
				}
				state = radio;
			}
		}
	}
	if (bns[2]) {
		bns[2] = false;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(" ");
		menu_index = (menu_index+5) % 6;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(">");
		wd_clock = 0; //reset activity
		watchdog_feed();
	}
	if (event_is_ready) {
		switch(next_event.id) {
			case start_ADC_conversion:
				ADC_start_conversion();
				set_brightness(photo_avg/PHOTO_AVG_RESOLUTION);
				schedule_insert(system_schedule, 20, ms_clock, start_ADC_conversion);
				break;
			
			default:
				break;
		}
	}
	if(wd_clock == 60) {
		wd_clock = 0;
		state = last_state;
	}
}
void inline alarm_state() {
	if (init) {
		nokia5110_clear();
		nokia5110_drawSplash();
		
		schedule_insert(system_schedule, 0, ms_clock, get_time);
		schedule_insert(system_schedule, 0, ms_clock, start_ADC_conversion);
		
		if (state == alarm_A) {
			if (alarm_A_is_beep) {
				radio_is_on = false;
				what_the_beep = true;
				schedule_insert(system_schedule, 250, ms_clock, beep_off);
			} else {
				#ifndef USING_PRINTF
				PORTD &= ~_BV(0); // Turn the radio LED on
				#endif
				
				what_the_beep = false;
				radio_is_on = true;
				si4705_power_on();
				si4705_set_channel(channel);
				schedule_insert(system_schedule, 100, ms_clock, radio_volume_change);
			}
		} else {
			if (alarm_B_is_beep) {
				radio_is_on = false;
				what_the_beep = true;
				schedule_insert(system_schedule, 250, ms_clock, beep_off);
			} else {
				#ifndef USING_PRINTF
				PORTD &= ~_BV(0); // Turn the radio LED on
				#endif
				
				what_the_beep = false;
				radio_is_on = true;
				si4705_power_on();
				si4705_set_channel(channel);
				schedule_insert(system_schedule, 100, ms_clock, radio_volume_change);
			}
		}
		err = 25;
		set_volume(25);
		wd_clock = 0;
	}
	if(bns[0] || bns[2]) { // sleep
		bns[0] = bns[2] = false;
		if (state==alarm_A) {
			time_alarm_A.hour = time.hour;
			time_alarm_A.minute = time.minute + ALARM_SLEEP_TIME;
			if (time_alarm_A.minute >= 60) {
				time_alarm_A.minute -= 60;
				time_alarm_A.hour += 1;
				if (time_alarm_A.hour >= 24) {
					time_alarm_A.hour -= 24;
				}
			}
		}
		if (state==alarm_B) {
			time_alarm_B.hour = time.hour;
			time_alarm_B.minute = time.minute + ALARM_SLEEP_TIME;
			if (time_alarm_B.minute >= 60) {
				time_alarm_B.minute -= 60;
				time_alarm_B.hour += 1;
				if (time_alarm_B.hour >= 24) {
					time_alarm_B.hour -= 24;
				}
			}
		}
		state = last_state;
	}
	if(bns[1] || ((state == alarm_A) && !hol[3]) || ((state == alarm_B) && !hol[4])) { // silence....... or did we have that backwards
		bns[1] = false;
		if (state==alarm_A) {
			alarm_A_went_off_today = true;
		}
		if (state==alarm_B) {
			alarm_B_went_off_today = true;
		}
		state = last_state;
	}
	if (event_is_ready) {
		switch(next_event.id) {
			case start_ADC_conversion:
				ADC_start_conversion();
				set_brightness(photo_avg/PHOTO_AVG_RESOLUTION);
				schedule_insert(system_schedule, 20, ms_clock, start_ADC_conversion);
				break;
			
			case get_time:
				ds1307_getdate_s(&time);
				schedule_insert(system_schedule, 1000, ms_clock, get_time);
				break;
			
			case radio_volume_change:
				if (err < 175 || err < ADC_values[0]) {
					err ++;
					set_volume(err);
				} else {
					if (ADC_values[0] > 175) {
						set_volume(ADC_values[0]);
					} else {
						set_volume(175);
					}
				}
				schedule_insert(system_schedule, 100, ms_clock, radio_volume_change);
				break;
			
			case beep_off:
				set_volume(0);
				schedule_insert(system_schedule, 500, ms_clock, beep_on);
				break;
				
			case beep_on:
				if (err < 175 || err < ADC_values[0]) {
					err += 5;
					set_volume(err);
				} else {
					if (ADC_values[0] > 175) {
						set_volume(ADC_values[0]);
					} else {
						set_volume(175);
					}
				}
				schedule_insert(system_schedule, 250, ms_clock, beep_off);
				break;
			
			default:
				break;
		}
	}
	if (wd_clock == 3599) {
		if (state==alarm_A) {
			alarm_A_went_off_today = true;
		}
		if (state==alarm_B) {
			alarm_B_went_off_today = true;
		}
		state = last_state;
	}
}
void inline menu_state() {
	if (init) {
		schedule_insert(system_schedule, 0, ms_clock, start_ADC_conversion);
		
		menu_index = 0;
		nokia5110_clear();
		nokia5110_gotoXY(0,0);
		if (last_state == home) {
			nokia5110_writeString(">Radio");
		} else {
			nokia5110_writeString(">Radio Off");
		}
		nokia5110_gotoXY(0,1);
		nokia5110_writeString(" Time-Set");
		nokia5110_gotoXY(0,2);
		nokia5110_writeString(" Set AlarmA");
		nokia5110_gotoXY(0,3);
		nokia5110_writeString(" Set AlarmB");
		nokia5110_gotoXY(0,4);
		if (last_state == home) {
			nokia5110_writeString(" Set Presets");
		} else {
			nokia5110_writeString(" FM Presets");
		}
		
		nokia5110_gotoXY(0,5);
		nokia5110_writeString(" Back");
	}
	if (bns[0]) {
		bns[0] = false;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(" ");
		menu_index = (menu_index+1) % 6;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(">");
		wd_clock = 0; //reset activity
		watchdog_feed();
	}
	if(bns[1]) {
		bns[1] = false;
		switch(menu_index) {
			case 0:
				if (last_state == home) {
					state = radio; 
				} else {
					state = home; 
				} 
				break;
			case 1:
				state = set_clock; break;
			case 2:
				state = set_alarm_A; break;
			case 3:
				state = set_alarm_B; break;
			case 4:
				state = preset; break;
			default: 
				state = last_state; break;
		}	
	}
	if (bns[2]) {
		bns[2] = false;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(" ");
		menu_index = (menu_index+5) % 6;
		nokia5110_gotoXY(0, menu_index);
		nokia5110_writeString(">");
		wd_clock = 0; //reset activity
		watchdog_feed();
	}
	if (event_is_ready) {
		switch(next_event.id) {
			case start_ADC_conversion:
				ADC_start_conversion();
				set_brightness(photo_avg/PHOTO_AVG_RESOLUTION);
				schedule_insert(system_schedule, 20, ms_clock, start_ADC_conversion);
				break;
			
			default:
				break;
		}
	}
	if(wd_clock == 60) {
		wd_clock = 0;
		state = last_state;
	}
}
void inline home_state() {
	if (init) {
		schedule_insert(system_schedule, 0, ms_clock, get_time);
		schedule_insert(system_schedule, 0, ms_clock, display_home_screen);
		schedule_insert(system_schedule, 0, ms_clock, display_temp_and_alarm_settings);
		schedule_insert(system_schedule, 0, ms_clock, start_ADC_conversion);
		
		nokia5110_clear();
		if (radio_is_on) {
			si4705_power_off();
			radio_is_on = false;
		}
		what_the_beep = false;
		set_volume(0);
		
		#ifndef USING_PRINTF
		PORTD |= _BV(0); // Turn the radio LED off
		PORTD |= _BV(1); // Turn the stereo status LED off
		#endif
	}
	if(bns[0]) {
		bns[0] = false;
	}
	if(bns[1]) {
		bns[1] = false;
		state = menu;
	}
	if(bns[2]) {
		bns[2] = false;
	}
	if (event_is_ready) {
		switch(next_event.id) {
			case start_ADC_conversion:
				ADC_start_conversion();
				set_brightness(photo_avg/PHOTO_AVG_RESOLUTION);
				schedule_insert(system_schedule, 20, ms_clock, start_ADC_conversion);
				break;
		
			case get_time:
				ds1307_getdate_s(&time);
				err = ds1307_getdayofweek(time.year, time.month, time.day);
				schedule_insert(system_schedule, 1000, ms_clock, get_time);
				//printf("%d:%d:%d\n", time.hour, time.minute, time.second);
				break;
		
			case display_home_screen:
				snprintf(line, 12, "%02d:%02d", time.hour - 12*(time.hour>12), time.minute);
				nokia5110_gotoXY(12,1);
				nokia5110_writeString_megaFont(line);
		
				snprintf(line, 12, " %s  ", days_of_week[err]);
				nokia5110_gotoXY(day_pixel_offsets[err],0);
				nokia5110_writeString(line);
		
				snprintf(line, 12, "%s", time.hour<12?"am":"pm");
				nokia5110_gotoXY(68,3);
				nokia5110_writeString(line);
		
				snprintf(line, 9, "%d/%d/%d   ", time.month, time.day, time.year);
				nokia5110_gotoXY(0,4);
				nokia5110_writeString(line);
		
				schedule_insert(system_schedule, 1000, ms_clock, display_home_screen);
				break;
		
			case display_temp_and_alarm_settings:
				init = false;
				snprintf(line, 8, "%02d.%01d%cF  ", (uint8_t)(temperature_avg/THERM_AVG_RESOLUTION/10), (uint8_t)(temperature_avg/THERM_AVG_RESOLUTION%10), 123);
				nokia5110_gotoXY(0,5);
				nokia5110_writeString(line);
			
				nokia5110_gotoXY(63,4);
				if (hol[3]) {
					snprintf(line, 4, "A:%c", alarm_A_is_beep?124+(ADC_values[0]>80)+(ADC_values[0]>180):127);
				} else {
					snprintf(line, 4, "A: ");
				}
				nokia5110_writeString(line);
				nokia5110_gotoXY(63,5);
				if (hol[4]) {
					snprintf(line, 4, "B:%c", alarm_B_is_beep?124+(ADC_values[0]>80)+(ADC_values[0]>180):127);
				} else {
					snprintf(line, 4, "B: ");
				}
				nokia5110_writeString(line);
				schedule_insert(system_schedule, 100, ms_clock, display_temp_and_alarm_settings);
				break;
			
			default:
				break;
		}
	}
	watchdog_feed();
}
Exemple #12
0
int schedule_insert(struct schedule_helper *sh, void *data,
                    int put_neg_in_current) {
  struct abstract_element *ae = (struct abstract_element *)data;

  if (put_neg_in_current && ae->t < sh->now) {
    /* insert item into current list */

    sh->current_count++;
    if (sh->current_tail == NULL) {
      sh->current = sh->current_tail = ae;
      ae->next = NULL;
    } else {
      sh->current_tail->next = ae;
      sh->current_tail = ae;
      ae->next = NULL;
    }
    return 0;
  }

  /* insert item into future lists */
  sh->count++;
  double nsteps = (ae->t - sh->now) * sh->dt_1;

  if (nsteps < ((double)sh->buf_len)) {
    /* item fits in array for this scale */

    int i;
    if (nsteps < 0.0)
      i = sh->index;
    else
      i = (int)nsteps + sh->index;
    if (i >= sh->buf_len)
      i -= sh->buf_len;

    if (sh->circ_buf_tail[i] == NULL) {
      sh->circ_buf_count[i] = 1;
      sh->circ_buf_head[i] = sh->circ_buf_tail[i] = ae;
      ae->next = NULL;
    } else {
      sh->circ_buf_count[i]++;

      /* For schedulers other than the first tier, maintain a LIFO ordering */
      if (sh->depth) {
        ae->next = sh->circ_buf_head[i];
        sh->circ_buf_head[i] = ae;
      }

      /* For first-tier scheduler, maintain FIFO ordering */
      else {
        sh->circ_buf_tail[i]->next = ae;
        ae->next = NULL;
        sh->circ_buf_tail[i] = ae;
      }
    }
  } else {
    /* item fits in array for coarser scale */

    if (sh->next_scale == NULL) {
      sh->next_scale = create_scheduler(
          sh->dt * sh->buf_len, sh->dt * sh->buf_len * sh->buf_len, sh->buf_len,
          sh->now + sh->dt * (sh->buf_len - sh->index));
      if (sh->next_scale == NULL)
        return 1;
      sh->next_scale->depth = sh->depth + 1;
    }

    /* insert item at coarser scale and insist that item is not placed in
     * "current" list */
    return schedule_insert(sh->next_scale, data, 0);
  }

  return 0;
}