硬汉嵌入式论坛

 找回密码
 立即注册
查看: 6911|回复: 8
收起左侧

[FatFs] UCOS下多任务fatfs的_FS_REENTRANT重入问题

[复制链接]

3

主题

27

回帖

36

积分

新手上路

积分
36
发表于 2015-12-3 14:54:35 | 显示全部楼层 |阅读模式
[paragraph] 在ucos下,使用fatfs文件系统,因为把文件系统有关的变量定义为全局变量,并且有多个任务需要调用fatfs文件系统的相关函数,
在网上比较了许多方法,有人使用关中断的方式,但是关中断造成的影响太严重了,还有使用调度锁的方法,比关中断好,但是
感觉用互斥信号量最合适,最终考虑使用互斥信号量,然后发现fatfs支持多任务操作系统的重入,借鉴安富莱综合例程,
下面是我的syscall.c源文件
  1. /*------------------------------------------------------------------------*/
  2. /* Sample code of OS dependent controls for FatFs                         */
  3. /* (C)ChaN, 2012                                                          */
  4. /*------------------------------------------------------------------------*/
  5. #include <stdlib.h>        /* ANSI memory controls */
  6. //#include <malloc.h>        /* ANSI memory controls */
  7. #include "ff.h"
  8. #if _FS_REENTRANT
  9. OS_MUTEX   SD_FILE_MUTEX;
  10. /*------------------------------------------------------------------------*/
  11. /* Create a Synchronization Object
  12. /*------------------------------------------------------------------------*/
  13. /* This function is called by f_mount() function to create a new
  14. /  synchronization object, such as semaphore and mutex. When a 0 is
  15. /  returned, the f_mount() function fails with FR_INT_ERR.
  16. */
  17. int ff_cre_syncobj (    /* 1:Function succeeded, 0:Could not create due to any error */
  18.     BYTE vol,            /* Corresponding logical drive being processed */
  19.     _SYNC_t* sobj        /* Pointer to return the created sync object */
  20. )
  21. {
  22.     int ret;
  23.     OS_ERR     err;
  24.   OSMutexCreate((OS_MUTEX  *)&SD_FILE_MUTEX, (CPU_CHAR *)"FatFSMutex",(OS_ERR    *)&err);
  25.    
  26.     *sobj = SD_FILE_MUTEX;
  27.    
  28.     ret = (int)(err == OS_ERR_NONE);
  29. //    *sobj = CreateMutex(NULL, FALSE, NULL);        /* Win32 */
  30. //    ret = (int)(*sobj != INVALID_HANDLE_VALUE);
  31. //    *sobj = SyncObjects[vol];        /* uITRON (give a static created semaphore) */
  32. //    ret = 1;
  33. //    *sobj = OSMutexCreate(0, &err);    /* uC/OS-II */
  34. //    ret = (int)(err == OS_NO_ERR);
  35. //  *sobj = xSemaphoreCreateMutex();    /* FreeRTOS */
  36. //    ret = (int)(*sobj != NULL);
  37.     return ret;
  38. }
  39. /*------------------------------------------------------------------------*/
  40. /* Delete a Synchronization Object                                        */
  41. /*------------------------------------------------------------------------*/
  42. /* This function is called in f_mount() function to delete a synchronization
  43. /  object that created with ff_cre_syncobj() function. When a 0 is
  44. /  returned, the f_mount() function fails with FR_INT_ERR.
  45. */
  46. int ff_del_syncobj (    /* 1:Function succeeded, 0:Could not delete due to any error */
  47.     _SYNC_t sobj        /* Sync object tied to the logical drive to be deleted */
  48. )
  49. {
  50.     int ret;
  51.   OS_ERR     err;
  52.    
  53.     OSMutexDel ((OS_MUTEX  *)&sobj,(OS_OPT     )OS_OPT_DEL_ALWAYS, (OS_ERR    *)&err);
  54.    
  55.     ret = (int)(err == OS_ERR_NONE);
  56. //    ret = CloseHandle(sobj);    /* Win32 */
  57. //    ret = 1;                    /* uITRON (nothing to do) */
  58. //    OSMutexDel(sobj, OS_DEL_ALWAYS, &err);    /* uC/OS-II */
  59. //    ret = (int)(err == OS_NO_ERR);
  60. //  xSemaphoreDelete(sobj);        /* FreeRTOS */
  61. //    ret = 1;
  62.     return ret;
  63. }
  64. /*------------------------------------------------------------------------*/
  65. /* Request Grant to Access the Volume                                     */
  66. /*------------------------------------------------------------------------*/
  67. /* This function is called on entering file functions to lock the volume.
  68. /  When a FALSE is returned, the file function fails with FR_TIMEOUT.
  69. */
  70. int ff_req_grant (    /* TRUE:Got a grant to access the volume, FALSE:Could not get a grant */
  71.     _SYNC_t sobj    /* Sync object to wait */
  72. )
  73. {
  74.     int ret;
  75.     OS_ERR     err;
  76.    
  77.     OSMutexPend ((OS_MUTEX  *)&sobj,(OS_TICK    )_FS_TIMEOUT,(OS_OPT     )OS_OPT_PEND_BLOCKING,(CPU_TS     )0,(OS_ERR    *)&err);   
  78.    
  79.     ret = (int)(err == OS_ERR_NONE);
  80. //    ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0);    /* Win32 */
  81. //    ret = (int)(wai_sem(sobj) == E_OK);            /* uITRON */
  82. //    OSMutexPend(sobj, _FS_TIMEOUT, &err));        /* uC/OS-II */
  83. //    ret = (int)(err == OS_NO_ERR);
  84. //    ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE);    /* FreeRTOS */
  85.     return ret;
  86. }
  87. /*------------------------------------------------------------------------*/
  88. /* Release Grant to Access the Volume                                     */
  89. /*------------------------------------------------------------------------*/
  90. /* This function is called on leaving file functions to unlock the volume.
  91. */
  92. void ff_rel_grant (
  93.     _SYNC_t sobj    /* Sync object to be signaled */
  94. )
  95. {
  96.     OS_ERR  err;
  97.     OSMutexPost ((OS_MUTEX  *)&sobj,(OS_OPT     )OS_OPT_POST_1,(OS_ERR    *)&err);
  98. //    ReleaseMutex(sobj);        /* Win32 */
  99. //    sig_sem(sobj);            /* uITRON */
  100. //    OSMutexPost(sobj);        /* uC/OS-II */
  101. //    xSemaphoreGive(sobj);    /* FreeRTOS */
  102. }
  103. #endif
  104. #if _USE_LFN == 3    /* LFN with a working buffer on the heap */
  105. /*------------------------------------------------------------------------*/
  106. /* Allocate a memory block                                                */
  107. /*------------------------------------------------------------------------*/
  108. /* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
  109. */
  110. void* ff_memalloc (    /* Returns pointer to the allocated memory block */
  111.     UINT msize        /* Number of bytes to allocate */
  112. )
  113. {
  114.     return malloc(msize);
  115. }
  116. /*------------------------------------------------------------------------*/
  117. /* Free a memory block                                                    */
  118. /*------------------------------------------------------------------------*/
  119. void ff_memfree (
  120.     void* mblock    /* Pointer to the memory block to free */
  121. )
  122. {
  123.     free(mblock);
  124. }
  125. #endif
复制代码
      但是在单步调试的过程中,发现互斥信号量的创建,接受都没问题,但是ff_rel_grant发送信号量是,返回的err是OS_ERR_MUTEX_NOT_OWNER,
然后单步调试安富莱的综合例程,也发现了同样的问题。不知该如何处理,前来请教。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2015-12-3 15:05:16 | 显示全部楼层
这个问题还真没注意过,后面研究下。
另外:
#define _FS_TIMEOUT        0            /* Timeout period in unit of time tick */ 是设置的一直等待吧。

返回这个错误说明这个任务不是互斥信号量拥有者,是另一个任务调用了此函数。
回复

使用道具 举报

3

主题

27

回帖

36

积分

新手上路

积分
36
 楼主| 发表于 2015-12-3 15:17:49 | 显示全部楼层

回 eric2013 的帖子

eric2013:
这个问题还真没注意过,后面研究下。
另外:
#define _FS_TIMEOUT        0            /* Timeout period in unit of time tick */ 是设置的一直等待吧。

返回这个错误说明这个任务不是互斥信号量拥有者,是另一个任务调用了此函数。
谢谢。
对,_FS_TIMEOUT 我设置的也是0。
问题是我在接受互斥信号量的ff_req_grant和发送信号量的ff_rel_grant各打了一个断点,
按道理不应该呀。

感觉用互斥信号量处理文件系统总是有问题。
我的调用方式是这样的,
  1. OSMutexPend();
  2. f_open();
  3. f_write();
  4. f_close();
  5. OSMutexPost();
复制代码
我建了三个测试任务,不停的往三个文件里写入,每写一次打印一次写入成功。就会发现过一阵子操作系统假死,感觉就好像是出现了死锁,然后过一阵子又自动恢复。
OSMutexPend()无论设置为阻塞还是非阻塞都会这样,很费解。。。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106934
QQ
发表于 2015-12-4 20:18:07 | 显示全部楼层

回 voidmain 的帖子

voidmain:谢谢。
对,_FS_TIMEOUT 我设置的也是0。
问题是我在接受互斥信号量的ff_req_grant和发送信号量的ff_rel_grant各打了一个断点,
按道理不应该呀。
....... (2015-12-03 15:17) 
看了一下,觉得是不是测试的问题,
你的底层已经加上互斥操作了,测试代码就不需要加互斥操作了
OSMutexPend();
f_open();
f_write();
f_close();
OSMutexPost();
回复

使用道具 举报

3

主题

27

回帖

36

积分

新手上路

积分
36
 楼主| 发表于 2015-12-7 12:30:23 | 显示全部楼层

回 eric2013 的帖子

eric2013:

看了一下,觉得是不是测试的问题,
你的底层已经加上互斥操作了,测试代码就不需要加互斥操作了
OSMutexPend();
f_open();
.......
应该不是,我测咱们安富莱的综合例程,也是这个现象,也会出现OS_ERR_MUTEX_NOT_OWNER

我在外面加互斥锁是想锁住文件系统的变量,因为我把文件系统的相关变量定义成全局的了,并且多个任务都会调用文件系统。
例如
  1. FIL file;
  2. f_open(&file, pname, FA_OPEN_ALWAYS);
  3. f_close(&file);
复制代码
我加锁是为了锁住file这个变量,防止多个任务同时操作file。
回复

使用道具 举报

5

主题

578

回帖

593

积分

版主

Rank: 7Rank: 7Rank: 7

积分
593
发表于 2015-12-16 09:40:23 | 显示全部楼层

回 voidmain 的帖子

voidmain:应该不是,我测咱们安富莱的综合例程,也是这个现象,也会出现OS_ERR_MUTEX_NOT_OWNER。

我在外面加互斥锁是想锁住文件系统的变量,因为我把文件系统的相关变量定义成全局的了,并且多个任务都会调用文件系统。
例如
....... (2015-12-07 12:30) 
同步量使用准则中,有个要求就是尽量避免在一个同步量临界区内又存在另一个同步量的临界区,或者是尽可能的减少重叠区域,多个临界区嵌套会造成系统分析复杂性成倍增加

硬汉兄已经给你指出了问题所在,如果可以还是在这个基础下重新设计你的代码结构吧
回复

使用道具 举报

5

主题

578

回帖

593

积分

版主

Rank: 7Rank: 7Rank: 7

积分
593
发表于 2015-12-16 09:52:24 | 显示全部楼层

回 voidmain 的帖子

voidmain:应该不是,我测咱们安富莱的综合例程,也是这个现象,也会出现OS_ERR_MUTEX_NOT_OWNER。

我在外面加互斥锁是想锁住文件系统的变量,因为我把文件系统的相关变量定义成全局的了,并且多个任务都会调用文件系统。
例如
....... (2015-12-07 12:30) 
flashfs是可以定义每个文件的打开句柄数的,fatfs应该也有这样的限制吧,你可以设置成只允许打开一个实例试试
回复

使用道具 举报

3

主题

27

回帖

36

积分

新手上路

积分
36
 楼主| 发表于 2015-12-17 14:09:29 | 显示全部楼层
因为内存比较紧张,我是想只定义一个FIL变量,然后使用它在多个任务中操作多个文件,所以考虑再加一个互斥锁。


我把测试代码的互斥操作取消了,试了下,ff_rel_grant发送信号量,返回的err还是OS_ERR_MUTEX_NOT_OWNER


安富莱综合例程也是这个现象。

回复

使用道具 举报

3

主题

27

回帖

36

积分

新手上路

积分
36
 楼主| 发表于 2015-12-29 11:06:10 | 显示全部楼层
临时的解决办法,不使用Fatfs的重入。暂时使用UCOS的调度锁。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 20:17 , Processed in 0.177606 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表