bluedroid alarm

alarm_new("btif_rc.rc_play_status_timer");
	alarm_new_internal(name, false);
		if (!alarms) //static list_t *alarms;
			lazy_initialize()
				alarms = list_new(NULL);
				if (!timer_create_internal(CLOCK_ID, &timer))
				if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer))
					struct sigevent sigevent;
					//使用线程方式,当timer到期之后,调用sigev_notify_function()
					sigevent.sigev_notify = SIGEV_THREAD;
					sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
						// timer到期后,Callback function for wake alarms and our posix timer
						static void timer_callback(UNUSED_ATTR void *ptr) {
						  semaphore_post(alarm_expired);
						}
					if (timer_create(clock_id, &sigevent, timer) == -1)
					
				//创建一个eventfd(value, EFD_SEMAPHORE);
				alarm_expired = semaphore_new(0);
				
				=====
				//创建一个默认的alarm线程
				default_callback_thread = thread_new_sized("alarm_default_callbacks", SIZE_MAX);
				//创建一个队列
				default_callback_queue = fixed_queue_new(SIZE_MAX);
				//将队列加入到线程里面去
				alarm_register_processing_queue(default_callback_queue, default_callback_thread);
					//把队列里面的dequeue_sem加入到线程的epoll监控里面去,当有消息时alarm_queue_ready函数会被调用
					fixed_queue_register_dequeue(
								queue,
								thread_get_reactor(thread),
								alarm_queue_ready,
								NULL);
								
				======
				//在之前的线程文章中说过,可以通过fixed_queue_register_dequeue添加新的队列和处理函数,比如:
				//通用的alarm队列
				btu_general_alarm_queue = fixed_queue_new(SIZE_MAX);
				//做了一个封装,公用alarm_queue_ready处理函数
				alarm_register_processing_queue(btu_general_alarm_queue, bt_workqueue_thread);
					fixed_queue_register_dequeue(queue, thread_get_reactor(thread),
                               alarm_queue_ready, NULL);
							   
				//从上面的函数可以看出,在bluedroid中会添加多个队列,但公用alarm_queue_ready一个处理函数
				alarm_queue_ready
					//从队列里面取出一个alarm
					alarm_t *alarm = (alarm_t *)fixed_queue_try_dequeue(queue);
					//执行即可
					alarm_callback_t callback = alarm->callback;
					callback(data);
					
				//继续分析lazy_initialize
				//创建一个线程
				dispatcher_thread = thread_new("alarm_dispatcher");
				//使用默认队列,传递处理函数
				thread_post(dispatcher_thread, callback_dispatch, NULL);
					//这个函数的目的是:当timer到期,把对应的消息放入到队列里面去处理
					callback_dispatch
						while (true) {//无限循环
							//等待alarm_expired ;timer到期后
							semaphore_wait(alarm_expired);

							//定时器到达之前可能被取消
							//定时器还未到达到期
							//退出,重新调度
							if (list_is_empty(alarms) ||
							(alarm = list_front(alarms))->deadline > now()) {
								reschedule_root_alarm();
								pthread_mutex_unlock(&monitor);
								continue;
							}
				
							list_remove(alarms, alarm);
							
							//执行完一个到期的定时器后,重新调动一个新的的timer
							reschedule_root_alarm();
							
							// Enqueue the alarm for processing
							// 放入alarm队列里面去执行
							fixed_queue_enqueue(alarm->queue, alarm);
						}

//下面有两种启动timer的方式
//指定队列
alarm_set_on_queue(btif_rc_cb.rc_play_status_timer,
                           BTIF_TIMEOUT_RC_INTERIM_RSP_MS,
                           btif_rc_play_status_timer_timeout, NULL,
                           btu_general_alarm_queue);
	alarm_set_on_queue(alarm, interval_ms, cb, data, btu_general_alarm_queue);

//默认队列							
alarm_set(btif_media_cb.media_alarm, BTIF_MEDIA_TIME_TICK,
						   btif_media_task_alarm_cb, NULL);
	alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue);
	
	
	alarm->creation_time = now();
	alarm->period = period; // 定时时间
	alarm->queue = queue; // default_callback_queue / btu_general_alarm_queue
	alarm->callback = cb; // btif_media_task_alarm_cb / btif_rc_play_status_timer_timeout
	alarm->data = data;

	schedule_next_instance(alarm);
		//如果已经添加了但还未执行,先删除掉,根据最新的重新排列
		if (alarm->callback)
			remove_pending_alarm(alarm)
	
		// 根据到期时间的大小进行排序,然后插入正确的位置
		// Calculate the next deadline for this alarm
		// Add it into the timer list sorted by deadline (earliest deadline first).
		static list_t *alarms;
		list_prepend(alarms, alarm);
		list_insert_after(alarms, node, alarm);
		
		// If the new alarm has the earliest deadline, we need to re-evaluate our schedule.
		if (needs_reschedule ||
			(!list_is_empty(alarms) && list_front(alarms) == alarm)) {
			reschedule_root_alarm(); //新的timer是最接近到期,马上调度
			
	alarm->stats.scheduled_count++;
	
最后看下:
reschedule_root_alarm
	// If used in a zeroed state, disarms the timer.
	struct itimerspec timer_time;
	memset(&timer_time, 0, sizeof(timer_time));
	
	//取出最接近到期的alarm
	const alarm_t *next = list_front(alarms);
	const int64_t next_expiration = next->deadline - now();

	//如果到期时间小于 int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; 3秒
	if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS)
		wakelock_acquire() //禁止休眠
		
		//计算到期时间
		timer_time.it_value.tv_sec = (next->deadline / 1000);
		timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;

		//???还没研究wakeup_timer
		// 猜测是唤醒系统的wakeup_timer
		// 此时已经禁止休眠,等待timer到期,应该删除wakeup_timer,但开销太大,所以设置一个很大很大的超时值
		struct itimerspec end_of_time;
		memset(&end_of_time, 0, sizeof(end_of_time));
		end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2));
		timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
	else
		struct itimerspec wakeup_time;
		memset(&wakeup_time, 0, sizeof(wakeup_time));


		wakeup_time.it_value.tv_sec = (next->deadline / 1000);
		wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
		//将到期时间设置为唤醒的timer值
		if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
	
	//If new_value->it_value specifies a zero value (i.e., both subfields are zero), then the timer is disarmed.
	// 0值的话,timer会被取消
	if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
	
	//考虑到一种情况,定时时间非常短,由于上下文??? 没有被执行,这里检测到这种情况,然后手动执行
	//执行两次也没关系
	if (timer_set) {
		struct itimerspec time_to_expire;
		timer_gettime(timer, &time_to_expire);
		if (time_to_expire.it_value.tv_sec == 0 &&
			time_to_expire.it_value.tv_nsec == 0) {
			LOG_DEBUG(LOG_TAG, "%s alarm expiration too close for posix timers, switching to guns", __func__);
			semaphore_post(alarm_expired);
		}
	}
总结:
1 timer 用来执行进程中所有的 alarm, alarms 保存根据时间排序组织成链表;
2 一类timer 只能一个执行完后,再次添加进去,再执行; 如果还没被执行时,再次被添加则取消前一个,重新排序;
3 当timer到期后,把消息放到队列去执行

	
	
	
	

猜你喜欢

转载自blog.csdn.net/x19910304xiaoyao/article/details/82958080
今日推荐