SMP结构中的中断机制和进程调度.ppt

上传人:s****8 文档编号:69446129 上传时间:2023-01-04 格式:PPT 页数:40 大小:168.50KB
返回 下载 相关 举报
SMP结构中的中断机制和进程调度.ppt_第1页
第1页 / 共40页
SMP结构中的中断机制和进程调度.ppt_第2页
第2页 / 共40页
点击查看更多>>
资源描述

《SMP结构中的中断机制和进程调度.ppt》由会员分享,可在线阅读,更多相关《SMP结构中的中断机制和进程调度.ppt(40页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、 Linux源代码阅读源代码阅读 SMP结构中的中断机制和进程调度张飞概要概要ppSMP结构中的中断机制p分布式中断处理分布式中断处理p中断初始化中断初始化p处理器间中断处理器间中断IPIIPIppSMP结构中的进程调度pp分布式中断处理pAPICAPIC简介简介pSMPSMP结构中的中断控制硬件机构结构中的中断控制硬件机构p全局全局APICAPICp本地本地APICAPIC高级可编程中断控制器高级可编程中断控制器APICpp为了充分利用为了充分利用smpsmp体系结构的并行性体系结构的并行性,要求动态分配中断请求要求动态分配中断请求,也就是说可以向任意也就是说可以向任意cpucpu发出中断请

2、求发出中断请求.pp传统的传统的i386i386处理器都采用处理器都采用8259A8259A中断控制器中断控制器,其作用是提供多个其作用是提供多个外部中断源与外部中断源与单一单一单一单一cpucpu之间的连接之间的连接.如果在如果在SMPSMP结构中还是采用结构中还是采用8259A8259A中断控制器中断控制器,那就只能静态的把所有的外部中断源划分成那就只能静态的把所有的外部中断源划分成若干组若干组,分别把每一组都连接到一个分别把每一组都连接到一个8259A,8259A,而而8259A8259A则与则与cpucpu有有一对一的连接一对一的连接.这样就达不到动态分配中断请求的目的这样就达不到动态

3、分配中断请求的目的.pp为了更好的支持为了更好的支持smpsmp结构结构,从从PentiumPentium开始开始,Intel,Intel设计了一种更设计了一种更为通用的中断控制器为通用的中断控制器,称为高级可编程中断控制器称为高级可编程中断控制器APIC APIC(Advanced Programmable Interrupt Controller).(Advanced Programmable Interrupt Controller).SMP结构中的中断控制硬件机构结构中的中断控制硬件机构cpu 0本地 APICcpu 1本地 APIC本地 APICcpu n全局APIC 本地中断请求

4、本地中断请求本地中断请求ICC(中断控制器通信)总线外部中断请求分布式中断处理硬件机制概述分布式中断处理硬件机制概述pp两种两种APIC:APIC:本地本地APICAPIC和全局和全局APIC,APIC,通过中断控通过中断控制器通信制器通信(Interrupt Controller(Interrupt Controller Communication,ICCCommunication,ICC)总线相连总线相连.pp本地本地APICAPIC集成在集成在cpucpu内部内部,通过内部通过内部APICAPIC可以可以向其他向其他cpucpu发送中断请求发送中断请求.pp全局全局APICAPIC负责把

5、来自外部设备的中断请求提负责把来自外部设备的中断请求提交和分配给系统中各个交和分配给系统中各个cpucpu的任务的任务.全局全局APICpp组成组成pp全局全局APICAPIC由一组由一组IRQIRQ线路线路,一个有一个有2424个表项的中断个表项的中断重定向表重定向表(Interrupt Redirection Table),(Interrupt Redirection Table),一个可编一个可编程寄存器和一个用来发送和接受经过程寄存器和一个用来发送和接受经过ICCICC总线的总线的APICAPIC消息的消息单元组成消息的消息单元组成.pp和和8259A8259A的的IRQIRQ引脚不同

6、引脚不同,中断优先级和引脚号无中断优先级和引脚号无关关,重定向表中的每个表项都可以被单独编程来说重定向表中的每个表项都可以被单独编程来说明中断向量和优先级明中断向量和优先级,目标处理器以及如何选定处目标处理器以及如何选定处理器理器.重定向表中的消息用来把外部重定向表中的消息用来把外部IRQIRQ信号转换信号转换成通过成通过ICCICC总线发往一个或多个本地总线发往一个或多个本地APICAPIC单元的消单元的消息息.全局全局APICpp工作模式工作模式pp固定模式固定模式 把把IRQIRQ信号发送到相应的重定向表表项所列出的本地信号发送到相应的重定向表表项所列出的本地 APICAPIC上上.pp

7、最低优先级模式最低优先级模式 把把IRQIRQ信号发送到正在执行优先级最低的进程的处理器信号发送到正在执行优先级最低的进程的处理器的本地的本地APICAPIC上上.所有的本地所有的本地APICAPIC都有一个可编程任务优都有一个可编程任务优先级寄存器先级寄存器(task priority register),(task priority register),它包含了当前正在运它包含了当前正在运行的进程的优先级行的进程的优先级.在每次任务切换时这个寄存器的值在每次任务切换时这个寄存器的值必须由内核进行修改必须由内核进行修改.本地本地APICpp组成组成 每个本地每个本地APICAPIC都有几个都

8、有几个3232位的寄存器位的寄存器,一个内部时钟一个内部时钟,一个定一个定时器设备时器设备,240,240个不同的中断向量个不同的中断向量(从从0 x200 xff,00 x1f0 x200 xff,00 x1f用于用于cpucpu本身的陷阱本身的陷阱)以及两条为局部中断保留的以及两条为局部中断保留的IRQIRQ线路线路,这两这两条线路用于重启系统条线路用于重启系统.pp本地本地APICAPIC的一个重要功能是实现处理器间中断的一个重要功能是实现处理器间中断IPIIPI 当一个当一个cpucpu想要向其他想要向其他cpucpu发送中断时发送中断时,将中断向量和目标处将中断向量和目标处理器的本地

9、理器的本地apicapic标志符保存到自己本地标志符保存到自己本地apicapic的中断命令寄存的中断命令寄存器中器中,然后通过然后通过ICCICC总线向目标处理器的本地总线向目标处理器的本地apicapic发送一条消发送一条消息息,目标处理器的本地目标处理器的本地apicapic就向自己的就向自己的cpucpu发出相应的中断发出相应的中断.SMP结构中的中断控制硬件机构结构中的中断控制硬件机构cpu 0本地 APICcpu 1本地 APIC本地 APICcpu n全局APIC 本地中断请求 本地中断请求本地中断请求ICC(中断控制器通信)总线外部中断请求概要概要ppSMP结构中的中断机制p分

10、布式中断处理分布式中断处理p中断初始化中断初始化p处理器间中断处理器间中断IPIIPIppSMP结构中的进程调度pp中断初始化psmpsmp相关的几个主要中断向量相关的几个主要中断向量p设置中断门设置中断门p中断响应程序的建立中断响应程序的建立p相关中断处理程序代码相关中断处理程序代码ppsmp_reschedule_interruptsmp_reschedule_interrupt()()ppsmp_call_function_interruptsmp_call_function_interrupt()()smp相关的几个主要中断向量相关的几个主要中断向量ppsmpsmp结构专用的几个结构专

11、用的几个IRQIRQ向量定义在向量定义在include/asm-include/asm-i386/apic.hi386/apic.h中中#define#define SPURIOUS_APIC_VECTOR SPURIOUS_APIC_VECTOR 0 xff0 xff#define#define ERROR_APIC_VECTOR ERROR_APIC_VECTOR 0 xfe0 xfe#define#define INVALIDATE_TLB_VECTOR INVALIDATE_TLB_VECTOR 0 xfd0 xfd#define#define RESCHEDULE_VECTOR RE

12、SCHEDULE_VECTOR 0 xfc0 xfc#define#define CALL_FUNCTION_VECTOR CALL_FUNCTION_VECTOR 0 xfb0 xfb#define#define LOCAL_TIMER_VECTOR LOCAL_TIMER_VECTOR 0 xef 0 xefpp其他不常用的向量合并到其他不常用的向量合并到CALL_FUNCTION_VECTORCALL_FUNCTION_VECTOR中以节省向量空间中以节省向量空间,使用比较频繁的是使用比较频繁的是TLBTLB、reschedulereschedule和和local APIClocal A

13、PIC中断向量中断向量.设置中断门设置中断门voidvoid _init_init init_IRQinit_IRQ(voidvoid)forfor(i=i=0 0;i i-funcfunc;/取出函数指取出函数指针针voidvoid *info=info=call_datacall_data-infoinfo;intint wait=wait=call_datacall_data-waitwait;ack_APIC_irqack_APIC_irq();();/先发回中断确认先发回中断确认atomic_incatomic_inc(&(&call_datacall_data-startedsta

14、rted););(*funcfunc)()(infoinfo););/调用指定函数调用指定函数if if(waitwait)/指定动作完成后指定动作完成后,wait,wait设置为设置为1 1atomic_incatomic_inc(&(&call_datacall_data-finishedfinished););具体中断处理程序具体中断处理程序ppsmp_call_function_interrupt()pp当然当然,一般的函数是没有必要请其他一般的函数是没有必要请其他CPUCPU来执行的来执行的,因为系统中所有的因为系统中所有的CPUCPU都可共享同样的代码和数都可共享同样的代码和数据据

15、.之所以要请求其他之所以要请求其他CPUCPU执行执行,是因为某个函数是因为某个函数必须由特定的必须由特定的CPUCPU来执行来执行.例如例如,pentiumpentium处理器有处理器有一条一条cpuidcpuid指令指令,通过这条指令可以查询本通过这条指令可以查询本CPUCPU的型的型号、版本以及是否支持一些特殊的功能、当前的号、版本以及是否支持一些特殊的功能、当前的功能设置等等信息功能设置等等信息.但是这条指令只能由具体的但是这条指令只能由具体的CPUCPU本身执行本身执行,而不能由别的而不能由别的CPUCPU代替代替.这样这样,如果如果要知道系统中某一个要知道系统中某一个CPUCPU的

16、有关情况的有关情况,就只能请求就只能请求该该CPUCPU来执行来执行cpuidcpuid指令指令.概述概述ppSMP结构中的中断机制p分布式中断处理分布式中断处理p中断初始化中断初始化p处理器间中断处理器间中断IPIIPIppSMP结构中的进程调度pp处理器间中断IPIpIPIIPI概述概述pIPIIPI中断向量中断向量pIPIIPI中断请求函数中断请求函数IPI概述概述n nIPI(IPI(InterprocessorInterprocessor Interrupt)Interrupt)称为处理机间中断称为处理机间中断.实实际上际上,前面介绍的前面介绍的RESCHEDULE_VECTORRE

17、SCHEDULE_VECTOR、INVALIDATE_TLB_VECTORINVALIDATE_TLB_VECTOR以及以及CALL_FUNCTION_VECTORCALL_FUNCTION_VECTOR都属于处理器间中断都属于处理器间中断IPI.IPI.n n从前一部分可以看出从前一部分可以看出,与单与单cpucpu系统的中断处理机制系统的中断处理机制相比相比,smpsmp系统仅仅作了少量修改系统仅仅作了少量修改,并且这些修改又大并且这些修改又大部分集中在处理器间中断部分集中在处理器间中断IPIIPI这一部分这一部分,也许我们可以也许我们可以从另一个角度来看待从另一个角度来看待smpsmp系

18、统的中断机制系统的中断机制-smpsmp中断中断机制和单机制和单CPUCPU系统中断机制在某种程度上是等价的系统中断机制在某种程度上是等价的.全局APICCPU 0CPU 1CPU n本地APIC本地APIC本地APIC外部中断外部中断CPU8259A单个“超级”处理器SMP结构与单CPU系统中断机制的类比IPI中断向量中断向量pp本地本地APICAPIC可以识别可以识别6 6种消息种消息,这些消息是由接收消息的这些消息是由接收消息的CPUCPU作为不同作为不同中断向量来解释的中断向量来解释的.(.(之所以不同于一般中断向量之所以不同于一般中断向量,可能是因为这些中可能是因为这些中断向量并不对

19、应着实际的中断请求引脚断向量并不对应着实际的中断请求引脚).).ppSPURIOUS_APIC_VECTOR(0 xff)SPURIOUS_APIC_VECTOR(0 xff)入口程序入口程序spurious_interruptspurious_interrupt(),(),实际中断处理程序实际中断处理程序smp_spurious_interruptsmp_spurious_interrupt().().ppERROR_APIC_VECTOR(0 xfe)ERROR_APIC_VECTOR(0 xfe)出错计数器溢出中断出错计数器溢出中断,入口程序入口程序error_interrupterro

20、r_interrupt(),(),中断处理程序中断处理程序smp_error_interruptsmp_error_interrupt().().ppINVALIDATE_TLB_VECTOR(0 xfd)INVALIDATE_TLB_VECTOR(0 xfd)ppRESCHEDULE_VECTOR(0 xfc)RESCHEDULE_VECTOR(0 xfc)ppCALL_FUNCTION_VECTOR(0 xfb)CALL_FUNCTION_VECTOR(0 xfb)ppLOCAL_TIMER_VECTOR(0 xef)LOCAL_TIMER_VECTOR(0 xef)I/O APIC I/

21、O APIC把定时中断自动发给所有的把定时中断自动发给所有的CPU.CPU.相应的入口程序是相应的入口程序是apic_timer_interruptapic_timer_interrupt(),(),实际中断服务程序为实际中断服务程序为smp_apic_timer_interruptsmp_apic_timer_interrupt().().中断请求函数中断请求函数pp中断请求函数用于向目标中断请求函数用于向目标CPUCPU发送指定的发送指定的IPIIPI请求向量请求向量ppstatic inline void static inline void send_IPI_allbutselfsen

22、d_IPI_allbutself(int(int vector)vector)向除自己以外的所有向除自己以外的所有CPUCPU发送一个发送一个IPI.IPI.ppstatic inline void static inline void send_IPI_allsend_IPI_all(int(int vector)vector)向所有的向所有的CPU(CPU(包括自己包括自己)发送一个发送一个IPI.IPI.ppvoid void send_IPI_selfsend_IPI_self(int(int vector)vector)向自己发送一个向自己发送一个IPI.IPI.ppstatic i

23、nline void static inline void send_IPI_masksend_IPI_mask(int(int mask,mask,intint vector)vector)向由向由maskmask指定的一个或多个指定的一个或多个CPUCPU发送一个发送一个IPI.IPI.pp这几个函数功能大同小异这几个函数功能大同小异,实现代码也都比较简单实现代码也都比较简单.其中以其中以send_IPI_masksend_IPI_mask函数最为灵活函数最为灵活,因而也稍为复杂一些因而也稍为复杂一些.send_IPI_masksend_IPI_mask函数函数函数函数static inl

24、ine voidstatic inline void send_IPI_masksend_IPI_mask(intint mask,mask,intint vector)vector)unsigned longunsigned long cfgcfg;unsigned longunsigned long flags;flags;_save_flagssave_flags(flagsflags););/中断前状态信息保存在中断前状态信息保存在flagsflags中中_clicli();();/关中断关中断 apic_wait_icr_idleapic_wait_icr_idle();();/确认

25、或等待确认或等待APIC_ICRAPIC_ICR处于空闲状处于空闲状态态 /*ICR2/*ICR2、ICRICR是本地是本地APICAPIC的的2 2个控制寄存器个控制寄存器*/cfgcfg=_prepare_ICR2prepare_ICR2(maskmask););/根据中断请求的目标根据中断请求的目标CPUCPU准备将要准备将要apic_write_aroundapic_write_around(APIC_ICR2APIC_ICR2,cfgcfg)/写入寄存器写入寄存器APIC_ICR2APIC_ICR2的值的值cfgcfg=_=_prepare_ICRprepare_ICR(0 0,ve

26、ctorvector););/根据要发送的中断向量准备将根据要发送的中断向量准备将要要apic_write_aroundapic_write_around(APIC_ICRAPIC_ICR,cfgcfg););/写入寄存器写入寄存器APIC_ICRAPIC_ICR的值的值/*/*对对APIC_ICRAPIC_ICR的写入操作引发并完成将中断向量发送至目标的写入操作引发并完成将中断向量发送至目标cpucpu的工作的工作*/_restore_flagsrestore_flags(flagsflags););/恢复标志恢复标志 static inline int _prepare_ICR2(unsi

27、gned int mask)return SET_APIC_DEST_FIELD(mask);static inline int _prepare_ICR(unsigned int shortcut,int vector)return APIC_DM_FIXED|shortcut|vector|APIC_DEST_LOGICAL;其他相关发送函数其他相关发送函数pp再看一个较为简单的函数再看一个较为简单的函数send_IPI_allsend_IPI_allstatic static inlineinline void void send_IPI_allsend_IPI_all(intint v

28、ector)vector)_send_IPI_shortcutsend_IPI_shortcut(APIC_DEST_ALLINCAPIC_DEST_ALLINC,vector);,vector);static static inlineinline void void _ _send_IPI_shortcutsend_IPI_shortcut(unsignedunsigned intint shortcut,shortcut,intint vector)vector)unsigned unsigned intint cfgcfg;apic_wait_icr_idleapic_wait_icr

29、_idle();();/确认或等待确认或等待ICRICR空闲空闲cfgcfg=_=_prepare_ICRprepare_ICR(shortcutshortcut,vectorvector);.);./对对ICRICR进行编程进行编程apic_write_aroundapic_write_around(APIC_ICRAPIC_ICR,cfgcfg););/*/*与与send_IPI_reschedulesend_IPI_reschedule相比相比,少了耗时的开少了耗时的开/关中断动作关中断动作,并且只对并且只对APICAPIC编程一次编程一次*/pp除除send_IPI_masksend_

30、IPI_mask()()之外的几个发送函数实际上都是简单的调用之外的几个发送函数实际上都是简单的调用_send_IPI_shortcutsend_IPI_shortcut函数函数,只不过传给这个函数的参数不同而已只不过传给这个函数的参数不同而已.在这些函数基础上在这些函数基础上,还定义了一些功能更为专一、明确的函数还定义了一些功能更为专一、明确的函数.比如当一个比如当一个CPUCPU需要需要另一个另一个CPUCPU进行一次进程调度时进行一次进程调度时,可以调用下面的函数可以调用下面的函数:voidvoid smp_send_reschedulesmp_send_reschedule(intin

31、t cpucpu)send_IPI_masksend_IPI_mask(1 1 )-has_cpuhas_cpu)&)&(p p)-)-cpus_allowedcpus_allowed&(&(1 1 -processorprocessor;/取得当前取得当前CPUCPU逻辑号逻辑号#ifdefifdef CONFIG_SMP CONFIG_SMP nextnext-has_cpuhas_cpu=1 1;/将要上台进程的将要上台进程的has_cpuhas_cpu设置为设置为1 1 nextnext-processorprocessor=this_cputhis_cpu;/设置设置processo

32、rprocessor字段字段#endifendif spin_unlock_irqspin_unlock_irq(&runqueue_lockrunqueue_lock););if if(prevprev=nextnext)gotogoto same_processsame_process;switch_toswitch_to(prevprev,nextnext,prevprev););/从从prevprev切换到切换到nextnext进程进程 _schedule_tailschedule_tail(prevprev););/处理下台的处理下台的prevprev进程进程,看能否在其他看能否在其

33、他cpucpu上重新调上重新调度度 static static inlineinline void void _ _schedule_tailschedule_tail(struct(struct task_structtask_struct *prevprev)函数函数函数函数保存先前进程调度策略并清零prev-policy中SCHED_YIELD标志位将prev的has_cpu字段清零下台前运行态?“空转”进程或自动下台?之前是运行态?尝试重新调度prev进程开始返回policy=prev-policy;prev-policy=policy&SCHED_YIELD;wmb();task_l

34、ock(prev);prev-has_cpu=0;mb();NYYNNYif(prev-state=TASK_RUNNING)if(prev=idle_task(smp_processor_id()|(policy&SCHED_YIELD)if(prev-state=TASK_RUNNING)reschedule_idle(prev);static voidstatic void reschedule_idlereschedule_idle(struct(struct task_structtask_struct *p*p)函数函数函数函数static voidstatic void resc

35、hedule_idlereschedule_idle(struct(struct task_structtask_struct *p*p)#ifdefifdef CONFIG_SMP CONFIG_SMPintint this_cputhis_cpu=smp_processor_idsmp_processor_id();();/取得当前取得当前CPUCPU逻辑号逻辑号structstruct task_structtask_struct *tsktsk,*target_tsktarget_tsk;intint cpucpu,best_cpubest_cpu,i,i,max_priomax_pr

36、io;cycles_tcycles_t oldest_idleoldest_idle;best_cpubest_cpu=p p-processorprocessor;/最好可以在原来的最好可以在原来的CPUCPU上重新运行上重新运行if if(can_schedulecan_schedule(p p,best_cpubest_cpu)/可以在原来的可以在原来的CPUCPU上调度么上调度么tsktsk=idle_taskidle_task(best_cpubest_cpu););/取得该取得该CPUCPU的的”空转空转”进进程程if if(cpu_currcpu_curr(best_cpubes

37、t_cpu)=)=tsktsk)/判断目的判断目的CPUCPU是否空闲是否空闲 intint need_reschedneed_resched;send_now_idlesend_now_idle:need_reschedneed_resched=tsktsk-need_reschedneed_resched;/保存原先的保存原先的need_reschedneed_resched tsktsk-need_reschedneed_resched=1 1;/设置设置need_reschedneed_resched标志标志 /*/*如果如果need_reschedneed_resched为为-1,-

38、1,则没有必要发送则没有必要发送IPI,idleIPI,idle进程会自动监视该变量进程会自动监视该变量*/if if(best_cpubest_cpu !=this_cputhis_cpu)&)&!need_reschedneed_resched)/需要发送需要发送IPI?IPI?smp_send_reschedulesmp_send_reschedule(best_cpubest_cpu););/发送发送RESCHEDULE_VECTORRESCHEDULE_VECTOR returnreturn;oldest_idleoldest_idle=(=(cycles_tcycles_t)-)-

39、1 1;target_tsktarget_tsk=NULLNULL;max_priomax_prio=1 1;/*/*查找所有可用查找所有可用CPU,CPU,看看能否重新调度进程看看能否重新调度进程p*/p*/forfor(i=(i=0 0;i ;i smp_num_cpussmp_num_cpus;i+);i+)/smp_num_cpussmp_num_cpus:系统中活动系统中活动CPUCPU个数个数cpucpu=cpu_logical_mapcpu_logical_map(i i););/取得该取得该CPUCPU的逻辑号的逻辑号if if(!can_schedulecan_schedul

40、e(p p,cpucpu)continuecontinue;tsktsk=cpu_currcpu_curr(cpucpu););if if(tsktsk=idle_taskidle_task(cpucpu)/存在空闲存在空闲CPU,CPU,选择运行时间最长的进程来剥选择运行时间最长的进程来剥夺夺if if(last_schedulelast_schedule(cpucpu)max_priomax_prio)/寻找一个运行资格较寻找一个运行资格较p p最低的进程来剥最低的进程来剥夺夺max_priomax_prio=prioprio;target_tsktarget_tsk=tsktsk;(接上

41、)tsktsk=target_tsktarget_tsk;if if(tsktsk)/如果存在可以剥夺的进程如果存在可以剥夺的进程if if(oldest_idleoldest_idle !=-1ULL-1ULL)/如果存在空闲如果存在空闲CPUCPUbest_cpubest_cpu=tsktsk-processorprocessor;gotogoto send_now_idlesend_now_idle;tsktsk-need_reschedneed_resched=1 1;/置置need_reschedneed_resched标志标志if if(tsktsk-processorproces

42、sor !=this_cputhis_cpu)smp_send_reschedulesmp_send_reschedule(tsktsk-processorprocessor););/发送发送IPIIPI returnreturn;#else#else/*/*ifundefifundef CONFIG_SMP*/CONFIG_SMP*/intint this_cputhis_cpu=smp_processor_idsmp_processor_id();();structstruct task_structtask_struct *tsktsk;tsktsk=cpu_currcpu_curr(this_cputhis_cpu););/取得当前进程取得当前进程if if(preemption_goodnesspreemption_goodness(tsktsk,p p,this_cputhis_cpu)1 1)/运行资格高于当前进运行资格高于当前进程程tsktsk-need_reschedneed_resched=1 1;#endifendif(接上)谢谢大家谢谢大家!

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 生活休闲 > 生活常识

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁