4.2.6 任务删除--vTaskDelete
这个接口并不复杂,主要是在判断是否要放到xTasksWaitingTermination列表里,还是直接处理。
vTaskDelete
- 1 static void prvDeleteTCB( TCB_t * pxTCB )
- 2 {
- 3 #if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )
- 4 {
- 5 /* The task can only have been allocated dynamically - free both
- 6 * the stack and TCB. */
- 7 vPortFreeStack( pxTCB->pxStack );
- 8 vPortFree( pxTCB );
- 9 }
- 10 #elif ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
- 11 {
- 12 /* The task could have been allocated statically or dynamically, so
- 13 * check what was statically allocated before trying to free the
- 14 * memory. */
- 15 /* 按需释放tcb和stack */
- 16 if( pxTCB->ucStaticallyAllocated == tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )
- 17 {
- 18 /* Both the stack and TCB were allocated dynamically, so both
- 19 * must be freed. */
- 20 vPortFreeStack( pxTCB->pxStack );
- 21 vPortFree( pxTCB );
- 22 }
- 23 else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )
- 24 {
- 25 /* Only the stack was statically allocated, so the TCB is the
- 26 * only memory that must be freed. */
- 27 vPortFree( pxTCB );
- 28 }
- 29 else
- 30 {
- 31 /* Neither the stack nor the TCB were allocated dynamically, so
- 32 * nothing needs to be freed. */
- 33 configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );
- 34 mtCOVERAGE_TEST_MARKER();
- 35 }
- 36 }
- 37 #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
- 38 }
复制代码 prvDeleteTCB 4.2.7 获取任务状态--eTaskGetState
这个接口可以大致看出任务在哪些情况下会处于什么状态。
首先是返回值的说明:- 1 typedef enum
- 2 {
- 3 eRunning = 0, /* 运行态. */
- 4 eReady, /* 就绪态, 任务在 ready or pending ready 列表. */
- 5 eBlocked, /* 阻塞态. */
- 6 eSuspended, /* 挂起态, 任务在 挂起列表, 或处于无限延迟的阻塞中. */
- 7 eDeleted, /* 等待删除. */
- 8 eInvalid /* Used as an 'invalid state' value. */
- 9 } eTaskState;
复制代码 eTaskGetState4.2.8 任务延迟,释放CPU--vTaskDelay
这个接口比较熟悉,至少是任务中最常用的接口了。但是正如接口的注释所说的那样,这个接口不提供准确的延迟时间,任务唤醒的周期会受中断、其他任务的影响,并且计时起始于这个接口开始被调用的时候,且时间是大于等于给予的延迟时间。如果想要准确的周期性的任务,那就要调用xTaskDelayUntil接口,这个会在后面讲到。
- 1 void vTaskDelay( const TickType_t xTicksToDelay )
- 2 {
- 3 BaseType_t xAlreadyYielded = pdFALSE;
- 4
- 5 /* A delay time of zero just forces a reschedule. */
- 6 /* 如果延迟tick为0, 则表示强制执行调度 */
- 7 if( xTicksToDelay > ( TickType_t ) 0U )
- 8 {
- 9 vTaskSuspendAll(); // 停止调度器
- 10 {
- 11 configASSERT( uxSchedulerSuspended == 1U );
- 12
- 13 /* A task that is removed from the event list while the
- 14 * scheduler is suspended will not get placed in the ready
- 15 * list or removed from the blocked list until the scheduler
- 16 * is resumed.
- 17 *
- 18 * This task cannot be in an event list as it is the currently
- 19 * executing task. */
- 20 /* 在调度器暂停时, 从事件列表中删除的任务将不会被放置在就绪列表中
- 21 * 或从阻塞列表中删除, 直到调度器恢复。此任务不可能在事件列表中,
- 22 * 因为它是当前正在执行的任务。 */
- 23 prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
- 24 }
- 25 xAlreadyYielded = xTaskResumeAll();
- 26 }
- 27 else
- 28 {
- 29 mtCOVERAGE_TEST_MARKER();
- 30 }
- 31
- 32 /* Force a reschedule if xTaskResumeAll has not already done so, we may
- 33 * have put ourselves to sleep. */
- 34 /* xTaskResumeAll没有调度, 那在这里手动调度 */
- 35 if( xAlreadyYielded == pdFALSE )
- 36 {
- 37 taskYIELD_WITHIN_API();
- 38 }
- 39 else
- 40 {
- 41 mtCOVERAGE_TEST_MARKER();
- 42 }
- 43 }
- 44
- 45 void vTaskSuspendAll( void )
- 46 {
- 47 #if ( configNUMBER_OF_CORES == 1 )
- 48 {
- 49 /* A critical section is not required as the variable is of type
- 50 * BaseType_t. Please read Richard Barry's reply in the following link to a
- 51 * post in the FreeRTOS support forum before reporting this as a bug! -
- 52 * https://goo.gl/wu4acr */
- 53
- 54 /* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that
- 55 * do not otherwise exhibit real time behaviour. */
- 56 portSOFTWARE_BARRIER();
- 57
- 58 /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
- 59 * is used to allow calls to vTaskSuspendAll() to nest. */
- 60 /* uxSchedulerSuspended非0, 则调度器暂停, 加1是为了嵌套调用(中断也调用) */
- 61 uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended + 1U );
- 62
- 63 /* Enforces ordering for ports and optimised compilers that may otherwise place
- 64 * the above increment elsewhere. */
- 65 portMEMORY_BARRIER();
- 66 }
- 67 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 68 }
- 69
- 70 static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
- 71 const BaseType_t xCanBlockIndefinitely )
- 72 {
- 73 TickType_t xTimeToWake;
- 74 const TickType_t xConstTickCount = xTickCount;
- 75 List_t * const pxDelayedList = pxDelayedTaskList;
- 76 List_t * const pxOverflowDelayedList = pxOverflowDelayedTaskList;
- 77
- 78 #if ( INCLUDE_xTaskAbortDelay == 1 )
- 79 {
- 80 /* About to enter a delayed list, so ensure the ucDelayAborted flag is
- 81 * reset to pdFALSE so it can be detected as having been set to pdTRUE
- 82 * when the task leaves the Blocked state. */
- 83 pxCurrentTCB->ucDelayAborted = ( uint8_t ) pdFALSE;
- 84 }
- 85 #endif
- 86
- 87 /* Remove the task from the ready list before adding it to the blocked list
- 88 * as the same list item is used for both lists. */
- 89 /* 将当前任务移出的列表必然是就绪列表, 移出后的就绪列表的item数量为0, 表示
- 90 * 就绪列表为空了, 需要重置下uxTopReadyPriority */
- 91 if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
- 92 {
- 93 /* The current task must be in a ready list, so there is no need to
- 94 * check, and the port reset macro can be called directly. */
- 95 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
- 96 }
- 97 else
- 98 {
- 99 mtCOVERAGE_TEST_MARKER();
- 100 }
- 101
- 102 #if ( INCLUDE_vTaskSuspend == 1 )
- 103 {
- 104 if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
- 105 {
- 106 /* Add the task to the suspended task list instead of a delayed task
- 107 * list to ensure it is not woken by a timing event. It will block
- 108 * indefinitely. */
- 109 /* 无限等待, 就加入到挂起列表里 */
- 110 listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
- 111 }
- 112 else
- 113 {
- 114 /* Calculate the time at which the task should be woken if the event
- 115 * does not occur. This may overflow but this doesn't matter, the
- 116 * kernel will manage it correctly. */
- 117 /* 计算延迟结束的tick */
- 118 xTimeToWake = xConstTickCount + xTicksToWait;
- 119
- 120 /* The list item will be inserted in wake time order. */
- 121 /* 说明xStateListItem的项里的值, 放的是wake的时间点 */
- 122 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
- 123
- 124 if( xTimeToWake < xConstTickCount )
- 125 {
- 126 /* Wake time has overflowed. Place this item in the overflow
- 127 * list. */
- 128 /* 处理数值溢出的情况, 说明wake的tick值溢出的话, 任务就在pxOverflowDelayedTaskList
- 129 * 列表里, 这是freeRTOS处理tick溢出的方式, 即用两个delay列表交替使用来处理 */
- 130 traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
- 131 vListInsert( pxOverflowDelayedList, &( pxCurrentTCB->xStateListItem ) );
- 132 }
- 133 else
- 134 {
- 135 /* The wake time has not overflowed, so the current block list
- 136 * is used. */
- 137 /* 没溢出就放到pxDelayedTaskList列表里, 一般一旦有溢出, 后面的任务
- 138 * 都是处于溢出的情况, 一旦tick加到0了, 就会交换pxDelayedTaskList
- 139 * 和pxOverflowDelayedTaskList指向的列表, 这样就解决了溢出的问题 */
- 140 traceMOVED_TASK_TO_DELAYED_LIST();
- 141 vListInsert( pxDelayedList, &( pxCurrentTCB->xStateListItem ) );
- 142
- 143 /* If the task entering the blocked state was placed at the
- 144 * head of the list of blocked tasks then xNextTaskUnblockTime
- 145 * needs to be updated too. */
- 146 /* 更新最近唤醒任务的时间 */
- 147 if( xTimeToWake < xNextTaskUnblockTime )
- 148 {
- 149 xNextTaskUnblockTime = xTimeToWake;
- 150 }
- 151 else
- 152 {
- 153 mtCOVERAGE_TEST_MARKER();
- 154 }
- 155 }
- 156 }
- 157 }
- 158 #endif /* INCLUDE_vTaskSuspend */
- 159 }
复制代码 vTaskDelay vTaskDelay的流程图如下。
接着是vTaskDelay调用的几个接口,除了xTaskIncrementTick接口没有放进来,这个接口比较重要和复杂,后面专门会进行解析。
4.2.8.1 将当前任务加入到延迟列表--prvAddCurrentTaskToDelayedList
- 1 static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
- 2 const BaseType_t xCanBlockIndefinitely )
- 3 {
- 4 TickType_t xTimeToWake;
- 5 const TickType_t xConstTickCount = xTickCount;
- 6 List_t * const pxDelayedList = pxDelayedTaskList;
- 7 List_t * const pxOverflowDelayedList = pxOverflowDelayedTaskList;
- 8
- 9 #if ( INCLUDE_xTaskAbortDelay == 1 )
- 10 {
- 11 /* About to enter a delayed list, so ensure the ucDelayAborted flag is
- 12 * reset to pdFALSE so it can be detected as having been set to pdTRUE
- 13 * when the task leaves the Blocked state. */
- 14 pxCurrentTCB->ucDelayAborted = ( uint8_t ) pdFALSE;
- 15 }
- 16 #endif
- 17
- 18 /* Remove the task from the ready list before adding it to the blocked list
- 19 * as the same list item is used for both lists. */
- 20 /* 将当前任务移出的列表必然是就绪列表, 移出后的就绪列表的item数量为0, 表示
- 21 * 就绪列表为空了, 需要重置下uxTopReadyPriority */
- 22 if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
- 23 {
- 24 /* The current task must be in a ready list, so there is no need to
- 25 * check, and the port reset macro can be called directly. */
- 26 portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
- 27 }
- 28 else
- 29 {
- 30 mtCOVERAGE_TEST_MARKER();
- 31 }
- 32
- 33 #if ( INCLUDE_vTaskSuspend == 1 )
- 34 {
- 35 if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
- 36 {
- 37 /* Add the task to the suspended task list instead of a delayed task
- 38 * list to ensure it is not woken by a timing event. It will block
- 39 * indefinitely. */
- 40 /* 无限等待, 就加入到挂起列表里 */
- 41 listINSERT_END( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
- 42 }
- 43 else
- 44 {
- 45 /* Calculate the time at which the task should be woken if the event
- 46 * does not occur. This may overflow but this doesn't matter, the
- 47 * kernel will manage it correctly. */
- 48 /* 计算延迟结束的tick */
- 49 xTimeToWake = xConstTickCount + xTicksToWait;
- 50
- 51 /* The list item will be inserted in wake time order. */
- 52 /* 说明xStateListItem的项里的值, 放的是wake的时间点 */
- 53 listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
- 54
- 55 if( xTimeToWake < xConstTickCount )
- 56 {
- 57 /* Wake time has overflowed. Place this item in the overflow
- 58 * list. */
- 59 /* 处理数值溢出的情况, 说明wake的tick值溢出的话, 任务就在pxOverflowDelayedTaskList
- 60 * 列表里, 这是freeRTOS处理tick溢出的方式, 即用两个delay列表交替使用来处理 */
- 61 traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
- 62 vListInsert( pxOverflowDelayedList, &( pxCurrentTCB->xStateListItem ) );
- 63 }
- 64 else
- 65 {
- 66 /* The wake time has not overflowed, so the current block list
- 67 * is used. */
- 68 /* 没溢出就放到pxDelayedTaskList列表里, 一般一旦有溢出, 后面的任务
- 69 * 都是处于溢出的情况, 一旦tick加到0了, 就会交换pxDelayedTaskList
- 70 * 和pxOverflowDelayedTaskList指向的列表, 这样就解决了溢出的问题 */
- 71 traceMOVED_TASK_TO_DELAYED_LIST();
- 72 vListInsert( pxDelayedList, &( pxCurrentTCB->xStateListItem ) );
- 73
- 74 /* If the task entering the blocked state was placed at the
- 75 * head of the list of blocked tasks then xNextTaskUnblockTime
- 76 * needs to be updated too. */
- 77 /* 更新最近唤醒任务的时间 */
- 78 if( xTimeToWake < xNextTaskUnblockTime )
- 79 {
- 80 xNextTaskUnblockTime = xTimeToWake;
- 81 }
- 82 else
- 83 {
- 84 mtCOVERAGE_TEST_MARKER();
- 85 }
- 86 }
- 87 }
- 88 }
- 89 #endif /* INCLUDE_vTaskSuspend */
- 90 }
复制代码 prvAddCurrentTaskToDelayedList 4.2.8.2 停止所有任务(停止调度器)--vTaskSuspendAll
- 1 void vTaskSuspendAll( void )
- 2 {
- 3 #if ( configNUMBER_OF_CORES == 1 )
- 4 {
- 5 /* A critical section is not required as the variable is of type
- 6 * BaseType_t. Please read Richard Barry's reply in the following link to a
- 7 * post in the FreeRTOS support forum before reporting this as a bug! -
- 8 * https://goo.gl/wu4acr */
- 9
- 10 /* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that
- 11 * do not otherwise exhibit real time behaviour. */
- 12 portSOFTWARE_BARRIER();
- 13
- 14 /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
- 15 * is used to allow calls to vTaskSuspendAll() to nest. */
- 16 /* uxSchedulerSuspended非0, 则调度器暂停, 加1是为了嵌套调用(中断也调用) */
- 17 uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended + 1U );
- 18
- 19 /* Enforces ordering for ports and optimised compilers that may otherwise place
- 20 * the above increment elsewhere. */
- 21 portMEMORY_BARRIER();
- 22 }
- 23 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 24 }
复制代码 vTaskSuspendAll 4.2.8.3 继续所有任务(继续调度器)--xTaskResumeAll
这个接口返回的是否已经调度过。
- 1 BaseType_t xTaskResumeAll( void )
- 2 {
- 3 TCB_t * pxTCB = NULL;
- 4 BaseType_t xAlreadyYielded = pdFALSE;
- 5
- 6 {
- 7 /* It is possible that an ISR caused a task to be removed from an event
- 8 * list while the scheduler was suspended. If this was the case then the
- 9 * removed task will have been added to the xPendingReadyList. Once the
- 10 * scheduler has been resumed it is safe to move all the pending ready
- 11 * tasks from this list into their appropriate ready list. */
- 12 taskENTER_CRITICAL();
- 13 {
- 14 BaseType_t xCoreID;
- 15 xCoreID = ( BaseType_t ) portGET_CORE_ID(); // 单核默认返回0
- 16
- 17 /* If uxSchedulerSuspended is zero then this function does not match a
- 18 * previous call to vTaskSuspendAll(). */
- 19 /* vTaskSuspendAll和xTaskResumeAll成对调用, 所以前面必然是调用过了
- 20 * vTaskSuspendAll, 那么uxSchedulerSuspended必然大于0的 */
- 21 configASSERT( uxSchedulerSuspended != 0U );
- 22
- 23 uxSchedulerSuspended = ( UBaseType_t ) ( uxSchedulerSuspended - 1U );
- 24 portRELEASE_TASK_LOCK();
- 25
- 26 if( uxSchedulerSuspended == ( UBaseType_t ) 0U )
- 27 {
- 28 if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
- 29 {
- 30 /* Move any readied tasks from the pending list into the
- 31 * appropriate ready list. */
- 32 /* 为什么是xPendingReadyList, 因为调用vTaskSuspendAll后调度器暂停了,
- 33 * 如果在调用本接口前(本接口会进入临界区, 临界区会禁止所有系统中断)
- 34 * 有任务就绪了(中断、事件、通知等), 就会把任务放xPendingReadyList列表里 */
- 35 while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE )
- 36 {
- 37 /* 把xPendingReadyList里的所有任务一个一个放到就绪列表中 */
- 38 pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
- 39 listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
- 40 portMEMORY_BARRIER();
- 41 listREMOVE_ITEM( &( pxTCB->xStateListItem ) );
- 42 prvAddTaskToReadyList( pxTCB );
- 43
- 44 #if ( configNUMBER_OF_CORES == 1 )
- 45 {
- 46 /* If the moved task has a priority higher than the current
- 47 * task then a yield must be performed. */
- 48 /* 如果取出来的任务有优先级比当前任务高的, 就需要调度, 先置标志位 */
- 49 if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
- 50 {
- 51 xYieldPendings[ xCoreID ] = pdTRUE;
- 52 }
- 53 else
- 54 {
- 55 mtCOVERAGE_TEST_MARKER();
- 56 }
- 57 }
- 58 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 59 }
- 60
- 61 if( pxTCB != NULL )
- 62 {
- 63 /* A task was unblocked while the scheduler was suspended,
- 64 * which may have prevented the next unblock time from being
- 65 * re-calculated, in which case re-calculate it now. Mainly
- 66 * important for low power tickless implementations, where
- 67 * this can prevent an unnecessary exit from low power
- 68 * state. */
- 69 /* 任务在调度器暂停时解除阻塞, 立即计算可以防止下一个解除阻塞
- 70 * 时间被重新计算, 这对于低功耗无障碍实现非常重要,因为这可以
- 71 * 防止不必要地退出低功耗 */
- 72 prvResetNextTaskUnblockTime();
- 73 }
- 74
- 75 /* If any ticks occurred while the scheduler was suspended then
- 76 * they should be processed now. This ensures the tick count does
- 77 * not slip, and that any delayed tasks are resumed at the correct
- 78 * time.
- 79 *
- 80 * It should be safe to call xTaskIncrementTick here from any core
- 81 * since we are in a critical section and xTaskIncrementTick itself
- 82 * protects itself within a critical section. Suspending the scheduler
- 83 * from any core causes xTaskIncrementTick to increment uxPendedCounts. */
- 84 /* 在调度器停止的时候, tick增加是增加xPendedTicks这个值, 在这里恢复调度器
- 85 * 的时候需要把这些增加的xPendedTicks值处理掉, 在临界区调用xTaskIncrementTick
- 86 * 是安全的, 至于为什么在解析xTaskIncrementTick后应该会清楚 */
- 87 {
- 88 TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */
- 89
- 90 if( xPendedCounts > ( TickType_t ) 0U )
- 91 {
- 92 do
- 93 {
- 94 if( xTaskIncrementTick() != pdFALSE )
- 95 {
- 96 /* Other cores are interrupted from
- 97 * within xTaskIncrementTick(). */
- 98 xYieldPendings[ xCoreID ] = pdTRUE;
- 99 }
- 100 else
- 101 {
- 102 mtCOVERAGE_TEST_MARKER();
- 103 }
- 104
- 105 --xPendedCounts;
- 106 } while( xPendedCounts > ( TickType_t ) 0U );
- 107
- 108 xPendedTicks = 0;
- 109 }
- 110 else
- 111 {
- 112 mtCOVERAGE_TEST_MARKER();
- 113 }
- 114 }
- 115
- 116 /* 需要调度的话, 这里立即开始调度(实际应该是
- 117 * 等退出临界区后进入pendSV中断), 我暂时也不确定,
- 118 * 等有空了仿真调式看看 */
- 119 if( xYieldPendings[ xCoreID ] != pdFALSE )
- 120 {
- 121 #if ( configUSE_PREEMPTION != 0 )
- 122 {
- 123 xAlreadyYielded = pdTRUE;
- 124 }
- 125 #endif /* #if ( configUSE_PREEMPTION != 0 ) */
- 126
- 127 #if ( configNUMBER_OF_CORES == 1 )
- 128 {
- 129 taskYIELD_TASK_CORE_IF_USING_PREEMPTION( pxCurrentTCB );
- 130 }
- 131 #endif /* #if ( configNUMBER_OF_CORES == 1 ) */
- 132 }
- 133 else
- 134 {
- 135 mtCOVERAGE_TEST_MARKER();
- 136 }
- 137 }
- 138 }
- 139 else
- 140 {
- 141 mtCOVERAGE_TEST_MARKER();
- 142 }
- 143 }
- 144 taskEXIT_CRITICAL();
- 145 }
- 146
- 147 return xAlreadyYielded;
- 148 }
复制代码 xTaskResumeAll
这篇就解析到这里,里面有不少遗留的问题,相信在逐步解析的过程中会慢慢解决的。下一篇开始解析xTaskDelayUntil和vTaskPrioritySet等接口,一些简单的接口如uxTaskBasePriorityGet这些,应该会选一个举例,其他的可能就一笔带过了。
那么,下一篇再见。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |