影響網(wǎng)站權(quán)重的因素有哪些商戶如何做h5商城網(wǎng)站是什么意思
鶴壁市浩天電氣有限公司
2026/01/24 15:27:47
影響網(wǎng)站權(quán)重的因素有哪些,商戶如何做h5商城網(wǎng)站是什么意思,大連網(wǎng)絡(luò)公司哪個(gè)好,百度給企業(yè)做網(wǎng)站嗎隨著處理器主頻的越來越高#xff0c;每次讀寫一次磁盤要耗費(fèi)很多個(gè)時(shí)鐘周期來等待磁盤操作的完成#xff0c;與其傻傻等待#xff0c;在這等待的過程中我們可以做更多有意義的事情#xff0c;如當(dāng)?shù)谝粋€(gè)程序需要等待輸入輸出的時(shí)候#xff0c;切換到第二個(gè)程序來運(yùn)行每次讀寫一次磁盤要耗費(fèi)很多個(gè)時(shí)鐘周期來等待磁盤操作的完成與其傻傻等待在這等待的過程中我們可以做更多有意義的事情如當(dāng)?shù)谝粋€(gè)程序需要等待輸入輸出的時(shí)候切換到第二個(gè)程序來運(yùn)行第二個(gè)程序也等待輸入輸出的時(shí)候就可以切換到第三個(gè)程序以此類推。這就是多道程序的思想要實(shí)現(xiàn)一個(gè)多道程序操作系統(tǒng), 我們只需要實(shí)現(xiàn)以下兩點(diǎn)就可以了:在內(nèi)存中可以同時(shí)存在多個(gè)進(jìn)程在滿足某些條件的情況下, 可以讓執(zhí)行流在這些進(jìn)程之間切換什么是進(jìn)程 進(jìn)程 程序 執(zhí)行進(jìn)程是執(zhí)行中的程序除了可執(zhí)行代碼外還包含進(jìn)程的活動(dòng)信息和數(shù)據(jù)比如用來存放函數(shù)變量、局部變量、返回值的用戶棧存放進(jìn)程相關(guān)數(shù)據(jù)的數(shù)據(jù)段內(nèi)核中進(jìn)程間切換的內(nèi)核棧動(dòng)態(tài)分配的堆。上下文切換在yield-os.c中構(gòu)建了兩個(gè)執(zhí)行流不斷交替輸出A和B基本原理就是進(jìn)程A運(yùn)行的時(shí)候觸發(fā)了系統(tǒng)調(diào)用通過自陷指令陷入到內(nèi)核中根據(jù)__am_asm_trap(),A的上下文結(jié)構(gòu)(Context)將會(huì)被保存在A的棧上。系統(tǒng)調(diào)用完后通過__am_asm_trap()恢復(fù)A的上下文如果此時(shí)不恢復(fù)A的上下文而是恢復(fù)B的上下文那么執(zhí)行完__am_asm_trap()來看下yield-os.c執(zhí)行流是如何進(jìn)行進(jìn)程切換的。首先貼出它的代碼。這個(gè)PCB是union類型的而不是struct類型的原因如下定義數(shù)據(jù)的時(shí)候把PCB的stack??臻g和cp 記錄上下文指針的元數(shù)據(jù)存放在同一塊內(nèi)存上。即pcb.stack占滿整個(gè)PCB內(nèi)存,然后PCB.CP放在內(nèi)存的棧底。這樣在上下文恢復(fù)時(shí)用 cp 指向的地址就能直接恢復(fù)棧上保存的 Context。#define STACK_SIZE (4096 * 8)typedef union {uint8_t stack[STACK_SIZE];struct { Context *cp; }; //(context pointer)來記錄上下文結(jié)構(gòu)的位置} PCB;int main() {cte_init(schedule);pcb[0].cp kcontext((Area) { pcb[0].stack, pcb[0] 1 }, f, (void *)1L);pcb[1].cp kcontext((Area) { pcb[1].stack, pcb[1] 1 }, f, (void *)2L);yield();panic(Should not reach here!);}第一件事先初始化一下CTEcte_init的作用是定義了待會(huì)跳轉(zhuǎn)去異常處理的地址傳給mtvec然后注冊回調(diào)函數(shù)shedulebool cte_init(Context*(*handler)(Event, Context*)) {// initialize exception entryasm volatile(csrw mtvec, %0 : : r(__am_asm_trap)); //把a(bǔ)masmtrap的地址傳給mtvecuser_handler handler;return true;}這個(gè)static Context *schedule(Event ev, Context *prev) {current-cp prev;current (current pcb[0] ? pcb[1] : pcb[0]);return current-cp;}然后把執(zhí)行完cte_init(schedule)之后到了pcb[0].cp kcontext((Area) { pcb[0].stack, pcb[0] 1 }, f, (void *)1L);pcb[1].cp kcontext((Area) { pcb[1].stack, pcb[1] 1 }, f, (void *)2L);先來看下kcontext()的代碼。第一個(gè)參數(shù){ pcb[0].stack, pcb[0] 1 }就是??臻g隨后將函數(shù)名當(dāng)成指針函數(shù)f 會(huì)自動(dòng)“退化”為指向該函數(shù)的指針。于是此時(shí)entry就是f了。如果指針后面賦值為mepc(uintptr_t)entry那么就會(huì)自動(dòng)執(zhí)行函數(shù)f帶上參數(shù)1。下一行同理Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {Context *cp (Context *)(kstack.end - sizeof(Context));cp-mepc (uintptr_t)entry;cp-mstatus 0x1800;cp-gpr[10] (uintptr_t)arg; //a0傳參return cp;}隨后陷入yield()void yield() {#ifdef __riscv_easm volatile(li a5, -1; ecall);#elseasm volatile(li a7, -1; ecall);#endif}于是進(jìn)行ecall指令I(lǐng)NSTPAT(0000000 00000 00000 000 00000 11100 11, ecall , I, s-dnpc isa_raise_intr(11,s-pc);etrace());然后調(diào)用isa_raise_intr(11,s-pc)函數(shù)。word_t isa_raise_intr(word_t NO, vaddr_t epc) {/* TODO: Trigger an interrupt/exception with NO. 待辦事項(xiàng)使用“NO”觸發(fā)中斷/異常。* Then return the address of the interrupt/exception vector. 然后返回中斷/異常向量的地址*/cpu.mstatus 0x00001800;cpu.mepc epc;cpu.mcause NO;return cpu.mtvec;}此時(shí)PC會(huì)跳轉(zhuǎn)到之前定義的mtvec中也就是cte_init中的__am_asm_trap函數(shù)。__am_asm_trap:addi sp, sp, -CONTEXT_SIZEMAP(REGS, PUSH)csrr t0, mcausecsrr t1, mstatuscsrr t2, mepcSTORE t0, OFFSET_CAUSE(sp)STORE t1, OFFSET_STATUS(sp)STORE t2, OFFSET_EPC(sp)# set mstatus.MPRV to pass difftestli a0, (1 17)or t1, t1, a0csrw mstatus, t1mv a0, spcall __am_irq_handlemv sp, a0LOAD t1, OFFSET_STATUS(sp)LOAD t2, OFFSET_EPC(sp)csrw mstatus, t1csrw mepc, t2MAP(REGS, POP)addi sp, sp, CONTEXT_SIZEmret這個(gè)函數(shù)作用之前講過了將上下文保存在棧上然后調(diào)用handler之后還原現(xiàn)場但此時(shí)我們把a(bǔ)0作為參數(shù)給sp那就能做到線程切換具體來看代碼。會(huì)跳轉(zhuǎn)到__am_irq_handle這個(gè)函數(shù)看看他的源碼。Context* __am_irq_handle(Context *c) {if (user_handler) {Event ev {0};switch (c-mcause) {case 11:ev.eventEVENT_YIELD;if(c-GPR1!-1)ev.event EVENT_SYSCALL;c-mepc 4;break;default: ev.event EVENT_ERROR; break;}//printf(mcause %s
,c-mcause);c user_handler(ev, c); //調(diào)用之前注冊的handlerassert(c ! NULL);}return c;}目前識(shí)別出是yield之后然后調(diào)用之前注冊的回調(diào)函數(shù)。也就是shedulestatic Context *schedule(Event ev, Context *prev) {current-cp prev;current (current pcb[0] ? pcb[1] : pcb[0]);return current-cp;}可以看到cte_init()在trace中是這么傳遞參數(shù)的。image意思就是根據(jù)riscv地abi切換a0的值也就是切換線程隨后mv sp, a0LOAD t1, OFFSET_STATUS(sp)LOAD t2, OFFSET_EPC(sp)csrw mstatus, t1csrw mepc, t2MAP(REGS, POP)addi sp, sp, CONTEXT_SIZEmret恢復(fù)現(xiàn)場切換為B線程也就是所有寄存器什么通用寄存器堆mepc,mcause, mstatus, mepc都一模一樣。然后調(diào)用mretpc變成cpu.mepc于是跳到剛剛kcontext定義的entry中也就是f函數(shù)里面然后判斷參數(shù)是多少進(jìn)行對應(yīng)的輸出之后又陷入到y(tǒng)ield一直循環(huán)。