record.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include "record.h"
  2. #include "check.h"
  3. #include <cmsis_os2.h>
  4. #include <m-string.h>
  5. #include <m-dict.h>
  6. #define FURI_RECORD_FLAG_UPDATED 0x00000001U
  7. DICT_SET_DEF(osThreadIdSet, uint32_t)
  8. typedef struct {
  9. void* data;
  10. osThreadId_t owner;
  11. osThreadIdSet_t holders;
  12. } FuriRecord;
  13. DICT_DEF2(FuriRecordDict, string_t, STRING_OPLIST, FuriRecord, M_POD_OPLIST)
  14. typedef struct {
  15. osMutexId_t records_mutex;
  16. FuriRecordDict_t records;
  17. } FuriRecordData;
  18. FuriRecordData furi_record_data;
  19. void furi_record_init() {
  20. furi_record_data.records_mutex = osMutexNew(NULL);
  21. FuriRecordDict_init(furi_record_data.records);
  22. }
  23. FuriRecord* furi_record_get_or_create(string_t name_str) {
  24. FuriRecord* record = FuriRecordDict_get(furi_record_data.records, name_str);
  25. if(!record) {
  26. FuriRecord new_record;
  27. new_record.data = NULL;
  28. new_record.owner = NULL;
  29. osThreadIdSet_init(new_record.holders);
  30. FuriRecordDict_set_at(furi_record_data.records, name_str, new_record);
  31. record = FuriRecordDict_get(furi_record_data.records, name_str);
  32. }
  33. return record;
  34. }
  35. void furi_record_create(const char* name, void* data) {
  36. osThreadId_t thread_id = osThreadGetId();
  37. string_t name_str;
  38. string_init_set_str(name_str, name);
  39. // Acquire mutex
  40. furi_check(osMutexAcquire(furi_record_data.records_mutex, osWaitForever) == osOK);
  41. FuriRecord* record = furi_record_get_or_create(name_str);
  42. record->data = data;
  43. record->owner = thread_id;
  44. // For each holder set event flag
  45. osThreadIdSet_it_t it;
  46. for(osThreadIdSet_it(it, record->holders); !osThreadIdSet_end_p(it); osThreadIdSet_next(it)) {
  47. osThreadFlagsSet((osThreadId_t)*osThreadIdSet_ref(it), FURI_RECORD_FLAG_UPDATED);
  48. }
  49. // Release mutex
  50. furi_check(osMutexRelease(furi_record_data.records_mutex) == osOK);
  51. string_clear(name_str);
  52. }
  53. bool furi_record_destroy(const char* name) {
  54. osThreadId_t thread_id = osThreadGetId();
  55. string_t name_str;
  56. string_init_set_str(name_str, name);
  57. bool destroyed = false;
  58. furi_check(osMutexAcquire(furi_record_data.records_mutex, osWaitForever) == osOK);
  59. FuriRecord* record = FuriRecordDict_get(furi_record_data.records, name_str);
  60. if(record && record->owner == thread_id && osThreadIdSet_size(record->holders) == 0) {
  61. osThreadIdSet_clear(record->holders);
  62. FuriRecordDict_erase(furi_record_data.records, name_str);
  63. }
  64. furi_check(osMutexRelease(furi_record_data.records_mutex) == osOK);
  65. string_clear(name_str);
  66. return destroyed;
  67. }
  68. void* furi_record_open(const char* name) {
  69. osThreadId_t thread_id = osThreadGetId();
  70. string_t name_str;
  71. string_init_set_str(name_str, name);
  72. FuriRecord* record = NULL;
  73. while(1) {
  74. furi_check(osMutexAcquire(furi_record_data.records_mutex, osWaitForever) == osOK);
  75. record = furi_record_get_or_create(name_str);
  76. osThreadIdSet_push(record->holders, (uint32_t)thread_id);
  77. furi_check(osMutexRelease(furi_record_data.records_mutex) == osOK);
  78. // Check if owner is already arrived
  79. if(record->owner) {
  80. break;
  81. }
  82. // Wait for thread flag to appear
  83. osThreadFlagsWait(FURI_RECORD_FLAG_UPDATED, osFlagsWaitAny, osWaitForever);
  84. }
  85. string_clear(name_str);
  86. return record->data;
  87. }
  88. void furi_record_close(const char* name) {
  89. osThreadId_t thread_id = osThreadGetId();
  90. string_t name_str;
  91. string_init_set_str(name_str, name);
  92. furi_check(osMutexAcquire(furi_record_data.records_mutex, osWaitForever) == osOK);
  93. FuriRecord* record = FuriRecordDict_get(furi_record_data.records, name_str);
  94. osThreadIdSet_erase(record->holders, (uint32_t)thread_id);
  95. furi_check(osMutexRelease(furi_record_data.records_mutex) == osOK);
  96. string_clear(name_str);
  97. }