慢慢欣赏linux 之 last = switch_to(prev, next)分析

last = switch_to(prev, next); 为什么需要定义last作为调用switch_to之前的prev的引用
原因如下:

struct task_struct * switch_to(struct task_struct *prev,
		struct task_struct *next)
{
	... ...
	return cpu_switch_to(prev, next);
	=> .global cpu_switch_to
	cpu_switch_to:
		add     x8, x0, #THREAD_CPU_CONTEXT
		mov     x9, sp
		stp     x19, x20, [x8], #16
		stp     x21, x22, [x8], #16
		stp     x23, x24, [x8], #16
		stp     x25, x26, [x8], #16
		stp     x27, x28, [x8], #16
		stp     x29, x9, [x8], #16
		str     lr, [x8]

		add     x8, x1, #THREAD_CPU_CONTEXT
		ldp     x19, x20, [x8], #16
		ldp     x21, x22, [x8], #16
		ldp     x23, x24, [x8], #16
		ldp     x25, x26, [x8], #16
		ldp     x27, x28, [x8], #16
		ldp     x29, x9, [x8], #16
		ldr     lr, [x8]
		mov     sp, x9	// 切换了 sp, 导致 prev 的堆栈空间切换到了 next 空间的堆栈
		ret
}

我们再来看 switch_to 的调用者

static void __schedule(void)
{
	struct task_struct *prev, *next, *last;
	struct run_queue *rq = &g_rq;

	prev = current;
	=> #define current get_current()
		=> static inline struct task_struct *get_current(void)
		{
			return (struct task_struct *) (current_stack_pointer & ~(THREAD_SIZE - 1));
				=> register unsigned long current_stack_pointer asm ("sp");	// 这时 prev 指向的 sp 已经是 next 进程空间的堆栈
		}

	/* 检查是否在中断上下文中发生了调度 */
	schedule_debug(prev);

	/* 关闭中断包含调度器,以免中断发生影响调度器 */
	raw_local_irq_disable();

	if (prev->state)
		dequeue_task(rq, prev);

	next = pick_next_task(rq, prev);
	clear_task_resched(prev);
	if (next != prev) {
		last = switch_to(prev, next);
		/*
		 * switch_to函数是用来切换prev进程到next进程。
		 * switch_to函数执行完成之后,已经切换到next
		 * 进程,整个栈和时空都发生变化了,不能使用这
		 * 里的prev变量来表示prev进程,只能通过aarch64
		 * 的x0寄存器来获取prev进程的task_struct。
		 *
		 * 在switch_to函数使用x0寄存器来传递prev进程
		 * task_struct,返回值也是通过x0寄存器,因此
		 * 这里last变量表示prev进程的task_struct
		 */
		rq->nr_switches++;
		rq->curr = current;
	}

	/* 由next进程来收拾prev进程的现场 */
	schedule_tail(last);
}

参考:

ARM64体系结构编程与实践

/** * Copyright (c) 1996-2016 TP-Link Systems Inc. All rights reserved. * by Wang Xiaowei <wangxiaowei@tp-link.net> * * Implement simple list management for active disks. */ #include <stdlib.h> #include <stdio.h> #include "storage.h" #include "disk.h" #include "disk_list.h" #include "shmem.h" #include "base.h" void disk_list_add_tail(uint32_t disk_id) { struct disk *disk_tail = NULL; struct disk *disk_new = NULL; struct vlist_head *head = NULL; struct vlist_head *disk_entry = NULL; if (disk_id < 1 || disk_id > MAX_DISK_NUM) return; disk_new = get_disk_by_id(disk_id); disk_entry = &disk_new->vlist_entry; if (is_disk_on_list(disk_new)) { STM_INFO("Disk(%d) may have been added to the list already.", disk_id); return; } head = get_list_head(disk_new->mnt_info.type); if (!head) return; /* no disk on the list */ if (head->next == DISK_ID_ANY || head->prev == DISK_ID_ANY) { head->next = disk_id; head->prev = disk_id; /* It is not a circular list */ disk_entry->prev = DISK_ID_ANY; disk_entry->next = DISK_ID_ANY; } else { disk_tail = get_disk_by_id(head->prev); disk_entry->next = disk_tail->vlist_entry.next; disk_tail->vlist_entry.next = disk_id; disk_entry->prev = disk_tail->id; head->prev = disk_id; } } void disk_list_del(uint32_t disk_id) { struct disk *disk = NULL; struct disk *next_disk = NULL; struct disk *prev_disk = NULL; struct vlist_head *head = NULL; if (disk_id < 1 || disk_id > MAX_DISK_NUM) return; disk = get_disk_by_id(disk_id); if (!disk) return; if (!is_disk_on_list(disk)) { STM_INFO("Disk(%d) is not on any list.", disk_id); return; } head = get_list_head(disk->mnt_info.type); if (!head) return; if (disk->vlist_entry.prev != DISK_ID_ANY) { prev_disk = get_disk_by_id(disk->vlist_entry.prev); } if (disk->vlist_entry.next != DISK_ID_ANY) { next_disk = get_disk_by_id(disk->vlist_entry.next); } if (prev_disk == NULL) { /* it's the only node on list */ if (next_disk == NULL) { head->next = DISK_ID_ANY; head->prev = DISK_ID_ANY; } /* it's the first node on list */ else { head->next = disk->vlist_entry.next; next_disk->vlist_entry.prev = DISK_ID_ANY; } } else { /* it's the last and not first node on list */ if (next_disk == NULL) { head->prev = prev_disk->id; prev_disk->vlist_entry.next = DISK_ID_ANY; } /* it's a node in the middle of list */ else { prev_disk->vlist_entry.next = next_disk->id; next_disk->vlist_entry.prev = prev_disk->id; } } disk->vlist_entry.next = DISK_ID_ANY; disk->vlist_entry.prev = DISK_ID_ANY; } struct vlist_head *get_list_head(enum disk_type type) { switch (type) { case DISK_TYPE_LOCAL: return &g_disk_manager_shm.shm_ptr->g_local_disk_list_head; case DISK_TYPE_REMOTE: return &g_disk_manager_shm.shm_ptr->g_remote_disk_list_head; default: STM_WARN("Disk type(%d) is not supported.", type); return NULL; } } bool is_disk_on_list(struct disk *disk) { struct vlist_head *local_head = get_list_head(DISK_TYPE_LOCAL); struct vlist_head *remote_head = get_list_head(DISK_TYPE_REMOTE); if (!local_head || !remote_head) { return 0; } return !(disk->vlist_entry.next == DISK_ID_ANY && disk->vlist_entry.prev == DISK_ID_ANY && local_head->next != disk->id && remote_head->next != disk->id); }
12-19
LV_KEY_UP, LV_KEY_DOWN, LV_KEY_RIGHT, LV_KEY_LEFT这四个方向是指按钮焦点移动吗?现在按下没有动作,要怎么修改。按下LV_KEY_ENTER是可以有动作的static uint32_t keypad_get_key(void) { /*Your code comes here*/ if(!HAL_GPIO_ReadPin(GPIOD,GPIO_PIN_8)) return 5; if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12)) return 1; if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13)) return 2; if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14)) return 3; if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_15)) return 4; return 0; }static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { static uint32_t last_key = 0; /*Get the current x and y coordinates*/ mouse_get_xy(&data->point.x, &data->point.y); /*Get whether the a key is pressed and save the pressed key*/ uint32_t act_key = keypad_get_key(); // uint32_t act_key = debounced_keypad_read(); if(act_key != 0) { data->state = LV_INDEV_STATE_PR; /*Translate the keys to LVGL control characters according to your key definitions*/ switch(act_key) { case 1: act_key = LV_KEY_UP; break; case 2: act_key = LV_KEY_DOWN; break; case 3: act_key = LV_KEY_PREV; break; case 4: act_key = LV_KEY_NEXT; break; case 5: act_key = LV_KEY_ENTER; break; } last_key = act_key; } else { data->state = LV_INDEV_STATE_REL; } data->key = last_key; } keypad_init(); /*Register a keypad input device*/ lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_KEYPAD; indev_drv.read_cb = keypad_read; indev_keypad = lv_indev_drv_register(&indev_drv); /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`, *add objects to the group with `lv_group_add_obj(group, obj)` *and assign this input device to group to navigate in it: *`lv_indev_set_group(indev_keypad, group);`*/ keypad_group = lv_group_create(); lv_group_set_default(keypad_group); // 设为默认组 lv_indev_set_group(indev_keypad, keypad_group);
10-25
static U1 u1_s_DspMnscrlDefLnkUpdt(U1 u1_numcntt, ST_DMNSCRL_STCTL * stp_stctl, const ST_DMNSCRL_STCFG * stp_stcfg, U1 u1_tabactv, U1 u1_tabcntt) { U1 u1_rsult; U4 u4_supbit; U1 u1_cnt; U1 u1_jdglinkupdt; const ST_DMNLNKCFG * stp_linkcfg; U1 u1_numscrl; U1 u1_updtmd; U1 u1_linkcntt; U4 u4_jdgintrpt; U1 u1_prev; U1 u1_next; u1_rsult = (U1)TRUE; u4_supbit = stp_stctl->u4_cnttsup; stp_stctl->u1_scrlbegin = (U1)DMNSCRL_CNTTUNDEF; u1_jdglinkupdt = (U1)DMNSCRL_INTBKCALL; stp_linkcfg = stp_stcfg->stp_linkcfg; u1_numscrl = stp_stcfg->u1_numscrl; for(u1_cnt = (U1)0; ((u1_cnt < u1_numscrl)&&(u1_rsult == (U1)TRUE)); u1_cnt++){ u1_linkcntt = stp_linkcfg[u1_cnt].u1_linkcntt; if((stp_stctl->st_link[u1_linkcntt].sts.u1_prev < u1_numcntt) && (stp_stctl->st_link[u1_linkcntt].sts.u1_next < u1_numcntt)){ u1_jdglinkupdt |= (U1)DMNSCRL_INTLINKD; } else if(stp_stctl->st_link[u1_linkcntt].u2_cnttlink == (U2)DMNSCRL_UNLINKD){ u1_jdglinkupdt &= (U1)U1_MAX ^ (U1)DMNSCRL_INTLINKD; } else{ u1_rsult = (U1)FALSE; break; } if(u1_linkcntt == stp_stctl->st_sts->sts.u1_dmncntt){ u1_jdglinkupdt |= (U1)DMNSCRL_INTCRRNT; } else{ u1_jdglinkupdt &= (U1)U1_MAX ^ (U1)DMNSCRL_INTCRRNT; } u4_jdgintrpt = u4_supbit & stp_stcfg->stp_cnttinf[u1_linkcntt].u4_supbit; if(u4_jdgintrpt != (U4)0){ u1_jdglinkupdt |= (U1)DMNSCRL_INTINDCTD; if(stp_stctl->u1_scrlbegin >= u1_numcntt){ stp_stctl->u1_scrlbegin = u1_linkcntt; } } else{ u1_jdglinkupdt &= (U1)U1_MAX ^ (U1)DMNSCRL_INTINDCTD; } u1_jdglinkupdt &= (U1)DMNLNK_CNDMASK; u1_updtmd = u1_DMNSCRL_LNKUPDTMD[u1_jdglinkupdt]; switch(u1_updtmd){ case (U1)DMNLNK_NOP: break; case (U1)DMNLNK_RMV: u1_prev = stp_stctl->st_link[u1_linkcntt].sts.u1_prev; u1_next = stp_stctl->st_link[u1_linkcntt].sts.u1_next; stp_stctl->st_link[u1_prev].sts.u1_next = u1_next; stp_stctl->st_link[u1_next].sts.u1_prev = u1_prev; stp_stctl->st_link[u1_linkcntt].u2_cnttlink = (U2)DMNSCRL_UNLINKD; break; case (U1)DMNLNK_RMVNXT: u1_prev = stp_stctl->st_link[u1_linkcntt].sts.u1_prev; u1_next = stp_stctl->st_link[u1_linkcntt].sts.u1_next; #if (__DMNSCRL_RMVNXTJMPFST_SUP__ == 1) if(stp_stctl->u1_scrlbegin < u1_numcntt){ stp_stctl->st_sts->sts.u1_dmncntt = stp_stctl->u1_scrlbegin; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[stp_stctl->u1_scrlbegin].u1_defopt; } else{ stp_stctl->st_sts->sts.u1_dmncntt = u1_next; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[u1_next].u1_defopt; } #else stp_stctl->st_sts->sts.u1_dmncntt = u1_next; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[u1_next].u1_defopt; #endif stp_stctl->st_link[u1_prev].sts.u1_next = u1_next; stp_stctl->st_link[u1_next].sts.u1_prev = u1_prev; stp_stctl->st_link[u1_linkcntt].u2_cnttlink = (U2)DMNSCRL_UNLINKD; break; case (U1)DMNLNK_RMVNXT1ST: if(stp_stcfg->stp_cnttinf[stp_stctl->st_sts->sts.u1_dmncntt].fp_bkgnd != NULL){ stp_stctl->st_sts->u2_ctlsts = (stp_stcfg->stp_cnttinf[stp_stctl->st_sts->sts.u1_dmncntt].fp_bkgnd)(stp_stctl->st_sts->u2_ctlsts, (U1)DMNSCRL_BKGNDACT_INIT); } if(u1_tabactv == (U1)TRUE){ vd_DSPMNSCRL_LNKUPDTHOOK(); } u1_jdglinkupdt &= (U1)U1_MAX ^ (U1)DMNSCRL_INTBKCALL; u1_prev = stp_stctl->st_link[u1_linkcntt].sts.u1_prev; u1_next = stp_stctl->st_link[u1_linkcntt].sts.u1_next; if(stp_linkcfg[u1_cnt].u1_unlinkstck == (U1)TRUE){ stp_stctl->u1_unlinkstck = stp_stctl->st_sts->sts.u1_dmncntt; } #if (__DMNSCRL_RMVNXTJMPFST_SUP__ == 1) if(stp_stctl->u1_scrlbegin < u1_numcntt){ stp_stctl->st_sts->sts.u1_dmncntt = stp_stctl->u1_scrlbegin; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[stp_stctl->u1_scrlbegin].u1_defopt; } else{ stp_stctl->st_sts->sts.u1_dmncntt = u1_next; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[u1_next].u1_defopt; } #else stp_stctl->st_sts->sts.u1_dmncntt = u1_next; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[u1_next].u1_defopt; #endif #if (__DMNSCRL_RMVNXTJMPPRE_SUP__ == 1) if(u1_tabcntt == (U1)DMNSCRLTAB_ECO){ stp_stctl->st_sts->sts.u1_dmncntt = u1_prev; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[u1_prev].u1_defopt; } else{ /* Do nothing */ } #endif stp_stctl->st_link[u1_prev].sts.u1_next = u1_next; stp_stctl->st_link[u1_next].sts.u1_prev = u1_prev; stp_stctl->st_link[u1_linkcntt].u2_cnttlink = (U2)DMNSCRL_UNLINKD; break; case (U1)DMNLNK_INSAREA: u1_next = stp_stctl->st_link[stp_stctl->u1_scrlend].sts.u1_next; if((u1_next < u1_numcntt) &&(stp_stctl->u1_scrlend < u1_numcntt)){ stp_stctl->st_link[u1_linkcntt].sts.u1_prev = stp_stctl->u1_scrlend; stp_stctl->st_link[u1_linkcntt].sts.u1_next = u1_next; stp_stctl->st_link[stp_stctl->u1_scrlend].sts.u1_next = u1_linkcntt; stp_stctl->st_link[u1_next].sts.u1_prev = u1_linkcntt; stp_stctl->u1_scrlend = u1_linkcntt; if(stp_stctl->u1_unlinkstck == u1_linkcntt){ if(stp_stcfg->stp_cnttinf[stp_stctl->st_sts->sts.u1_dmncntt].fp_bkgnd != NULL){ stp_stctl->st_sts->u2_ctlsts = (stp_stcfg->stp_cnttinf[stp_stctl->st_sts->sts.u1_dmncntt].fp_bkgnd)(stp_stctl->st_sts->u2_ctlsts, (U1)DMNSCRL_BKGNDACT_INIT); } if(u1_tabactv == (U1)TRUE){ vd_DSPMNSCRL_LNKUPDTHOOK(); } stp_stctl->st_sts->sts.u1_dmncntt = u1_linkcntt; stp_stctl->st_sts->sts.u1_dmnopt = stp_stcfg->stp_cnttinf[u1_linkcntt].u1_defopt; stp_stctl->u1_unlinkstck = (U1)DMNSCRL_CNTTUNDEF; } } else{ u1_rsult = (U1)FALSE; /* error */ } break; case (U1)DMNLNK_UPDTLNKPT: stp_stctl->u1_scrlend = u1_linkcntt; break; default: u1_rsult = (U1)FALSE; /* error */ break; } } return(u1_rsult); }为补充函数
08-13
#include "./adc_key.h" #include "stm32f4xx.h" #include "stm32f4xx_adc.h" #include "./vs1053.h" extern uint8_t menu_mode; void ADC_KEY_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); GPIO_InitTypeDef gpio_init; gpio_init.GPIO_Pin = GPIO_Pin_0; gpio_init.GPIO_Mode = GPIO_Mode_AN; gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &gpio_init); ADC_InitTypeDef adc_init; adc_init.ADC_Resolution = ADC_Resolution_12b; adc_init.ADC_ScanConvMode = DISABLE; adc_init.ADC_ContinuousConvMode = ENABLE; adc_init.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; adc_init.ADC_DataAlign = ADC_DataAlign_Right; adc_init.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &adc_init); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_84Cycles); ADC_Cmd(ADC1, ENABLE); ADC_SoftwareStartConv(ADC1); } uint8_t ADC_KEY_Read(void) { uint16_t adc_val = ADC_GetConversionValue(ADC1); if (adc_val < 1000) return KEY_PLAY_PAUSE; else if (adc_val < 2000) return KEY_PREV_VOLUP; else if (adc_val < 3000) return KEY_NEXT_VOLDOWN; else return KEY_MENU_BACK; } void Key_Handler(void) { static uint32_t last_time = 0; static uint8_t key_state = 0; if (HAL_GetTick() - last_time < 20) return; last_time = HAL_GetTick(); uint8_t key = ADC_KEY_Read(); if (key != key_state) { key_state = key; return; } switch(key) { case KEY_PLAY_PAUSE: VS1053_PlayPause(); break; case KEY_PREV_VOLUP: if (menu_mode) VS1053_VolumeUp(); else Play_Prev(); break; case KEY_NEXT_VOLDOWN: if (menu_mode) VS1053_VolumeDown(); else Play_Next(); break; case KEY_MENU_BACK: Menu_Toggle(); break; } }将以上内容以SPL库重新编写代码
07-06
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值