写入flash页面时powerfail序列的死锁
我目前正在开发一个使用ARM Cortex M3微控制器和FreeRTOS作为系统操作系统的嵌入式项目.代码是由一位前同事编写的,遗憾的是该项目有一些奇怪的错误,我必须尽快找到并修复.
简短说明:该设备集成到车辆中,并使用集成调制解调器向远程服务器发送一些“特殊”数据. 主要问题:由于设备集成在车辆中,设备的电源可能随时丢失.因此,设备将“特殊”数据的某些部分存储到两个保留的闪存页面.此代码模块在两个闪存页面上作为eeprom仿真进行布局(用于从一个闪存页面到另一个闪存页面的耗损均衡和数据传输). 但是我的项目经理告诉我,设备总是会丢失一些“特殊”数据,车辆中的电源电压下降到几伏,设备会尝试将数据保存到闪存中. 在powerfail任务执行的那些回调中(称为powerfail回调),有RTOS调用, 这是将数据写入闪存的例程: uint16_t EE_WriteBlock (EE_TypeDef *EE,uint16_t VirtAddress,const void *Data,uint16_t Size) { . . xSemaphoreTakeRecursive(EE->rw_mutex,portMAX_DELAY); /* Write the variable virtual address and value in the EEPROM */ . . . xSemaphoreGiveRecursive(EE->rw_mutex); return Status; } 当调用’xSemaphoreTakeRecursive()’时,这是RTOS特定的代码: portBASE_TYPE xQueueTakeMutexRecursive( xQueueHandle pxMutex,portTickType xBlockTime ) { portBASE_TYPE xReturn; /* Comments regarding mutual exclusion as per those within xQueueGiveMutexRecursive(). */ traceTAKE_MUTEX_RECURSIVE( pxMutex ); if( pxMutex->pxMutexHolder == xTaskGetCurrentTaskHandle() ) { ( pxMutex->uxRecursiveCallCount )++; xReturn = pdPASS; } else { xReturn = xQueueGenericReceive( pxMutex,NULL,xBlockTime,pdFALSE ); /* pdPASS will only be returned if we successfully obtained the mutex,we may have blocked to reach here. */ if( xReturn == pdPASS ) { ( pxMutex->uxRecursiveCallCount )++; } else { traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); } } return xReturn; } 我的项目经理很高兴我发现了这个bug,但他也强迫我尽快创建一个修复程序,但我真正想要的是重写代码. 谢谢 解决方法
在许多系统上写入闪存需要在写入期间禁用中断,因此我不确定在写入过程中如何使powerFail运行,但无论如何:
不要使用互斥锁直接控制对保留的Flash页面的访问 – 请使用阻塞生成者 – 使用者队列. 通过将请求排队到一个’flashWriter’线程,将所有这些写入委托给它.如果请求写入的线程需要同步访问,请在请求结构中包含请求线程在推送其请求后等待的事件或信号量. flashWriter完成后可以发出信号(或者在加载带有错误指示的结构:)之后发出信号. 主题有变化 – 如果所有写请求线程只需要同步访问,也许他们可以使用自己的信号量保留自己的静态请求结构,并排队指向它的指针. 使用允许在队列头部进行高优先级推送的生产者 – 消费者队列类,并且当powerfail运行时,在队列的前面按下“stopWriting”请求.然后flashWriter将完成正在进行的任何写入操作,弹出stopWriting请求,因此被指示暂停自身,(或者您可以使用flashWriter每次尝试弹出队列之前检查的’stop’易失性布尔值). 这应该通过从其他线程中推送的闪存写入请求中删除硬互斥锁来防止死锁.其他线程是否继续排队写入请求并不重要 – 它们永远不会被执行. 编辑:我刚吃了两杯咖啡,考虑到这一点,’flashWriter’线程很容易成为’FlashWriterAndPowerFail’线程: 如果设置了volatile’stop’布尔值,则可以安排生产者 – 消费者队列返回null的pop()结果,无论队列中是否有条目或没有.在’FWAPF’线程中,在每次pop()返回后进行空检查,并在null时执行powerFail操作,否则执行flashWrite操作. 当powerFail中断发生时,设置stop bool并发出队列中’count’信号量的信号,以确保FWAPF线程在队列中当前被阻塞时运行. 这样,你不需要一个单独的’powerFail’线程和堆栈 – 一个线程可以执行flashWrite和powerFail,同时仍然确保没有互斥锁死锁. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |