RPC: Implement storage_stat_request (#800)
* RPC: Update protobuf sources * RPC: Implement storage_stat_request * RPC: Test storage_stat_request * FuriRecord: fix use after free in destroy method. * Furi: refactor PubSub and it's usage. Fix allocation in RPC. * FuriCore: fix memory leak in pubsub * FuriCore: update unsubscribe method signature in pubsub, make subscription structure lighter. * FuriCore: remove dead code Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -1,88 +1,95 @@
|
||||
#include "pubsub.h"
|
||||
#include <furi.h>
|
||||
#include "memmgr.h"
|
||||
#include "check.h"
|
||||
|
||||
#include <m-list.h>
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
struct FuriPubSubSubscription {
|
||||
FuriPubSubCallback callback;
|
||||
void* callback_context;
|
||||
};
|
||||
|
||||
LIST_DEF(FuriPubSubSubscriptionList, FuriPubSubSubscription, M_POD_OPLIST);
|
||||
|
||||
struct FuriPubSub {
|
||||
FuriPubSubSubscriptionList_t items;
|
||||
osMutexId_t mutex;
|
||||
};
|
||||
|
||||
FuriPubSub* furi_pubsub_alloc() {
|
||||
FuriPubSub* pubsub = furi_alloc(sizeof(FuriPubSub));
|
||||
|
||||
bool init_pubsub(PubSub* pubsub) {
|
||||
// mutex without name,
|
||||
// no attributes (unfortunatly robust mutex is not supported by FreeRTOS),
|
||||
// with dynamic memory allocation
|
||||
pubsub->mutex = osMutexNew(NULL);
|
||||
if(pubsub->mutex == NULL) return false;
|
||||
furi_assert(pubsub->mutex);
|
||||
|
||||
// construct list
|
||||
list_pubsub_cb_init(pubsub->items);
|
||||
FuriPubSubSubscriptionList_init(pubsub->items);
|
||||
|
||||
return true;
|
||||
return pubsub;
|
||||
}
|
||||
|
||||
bool delete_pubsub(PubSub* pubsub) {
|
||||
if(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK) {
|
||||
bool result = osMutexDelete(pubsub->mutex) == osOK;
|
||||
list_pubsub_cb_clear(pubsub->items);
|
||||
return result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void furi_pubsub_free(FuriPubSub* pubsub) {
|
||||
furi_assert(pubsub);
|
||||
|
||||
furi_check(FuriPubSubSubscriptionList_size(pubsub->items) == 0);
|
||||
|
||||
FuriPubSubSubscriptionList_clear(pubsub->items);
|
||||
|
||||
furi_check(osMutexDelete(pubsub->mutex) == osOK);
|
||||
|
||||
free(pubsub);
|
||||
}
|
||||
|
||||
PubSubItem* subscribe_pubsub(PubSub* pubsub, PubSubCallback cb, void* ctx) {
|
||||
if(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK) {
|
||||
// put uninitialized item to the list
|
||||
PubSubItem* item = list_pubsub_cb_push_raw(pubsub->items);
|
||||
FuriPubSubSubscription*
|
||||
furi_pubsub_subscribe(FuriPubSub* pubsub, FuriPubSubCallback callback, void* callback_context) {
|
||||
furi_check(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK);
|
||||
// put uninitialized item to the list
|
||||
FuriPubSubSubscription* item = FuriPubSubSubscriptionList_push_raw(pubsub->items);
|
||||
|
||||
// initialize item
|
||||
item->cb = cb;
|
||||
item->ctx = ctx;
|
||||
item->self = pubsub;
|
||||
// initialize item
|
||||
item->callback = callback;
|
||||
item->callback_context = callback_context;
|
||||
|
||||
// TODO unsubscribe pubsub on app exit
|
||||
//flapp_on_exit(unsubscribe_pubsub, item);
|
||||
furi_check(osMutexRelease(pubsub->mutex) == osOK);
|
||||
|
||||
osMutexRelease(pubsub->mutex);
|
||||
|
||||
return item;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
bool unsubscribe_pubsub(PubSubItem* pubsub_id) {
|
||||
if(osMutexAcquire(pubsub_id->self->mutex, osWaitForever) == osOK) {
|
||||
bool result = false;
|
||||
void furi_pubsub_unsubscribe(FuriPubSub* pubsub, FuriPubSubSubscription* pubsub_subscription) {
|
||||
furi_assert(pubsub);
|
||||
furi_assert(pubsub_subscription);
|
||||
|
||||
// iterate over items
|
||||
list_pubsub_cb_it_t it;
|
||||
for(list_pubsub_cb_it(it, pubsub_id->self->items); !list_pubsub_cb_end_p(it);
|
||||
list_pubsub_cb_next(it)) {
|
||||
const PubSubItem* item = list_pubsub_cb_cref(it);
|
||||
furi_check(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK);
|
||||
bool result = false;
|
||||
|
||||
// if the iterator is equal to our element
|
||||
if(item == pubsub_id) {
|
||||
list_pubsub_cb_remove(pubsub_id->self->items, it);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
// iterate over items
|
||||
FuriPubSubSubscriptionList_it_t it;
|
||||
for(FuriPubSubSubscriptionList_it(it, pubsub->items); !FuriPubSubSubscriptionList_end_p(it);
|
||||
FuriPubSubSubscriptionList_next(it)) {
|
||||
const FuriPubSubSubscription* item = FuriPubSubSubscriptionList_cref(it);
|
||||
|
||||
// if the iterator is equal to our element
|
||||
if(item == pubsub_subscription) {
|
||||
FuriPubSubSubscriptionList_remove(pubsub->items, it);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
osMutexRelease(pubsub_id->self->mutex);
|
||||
return result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
furi_check(osMutexRelease(pubsub->mutex) == osOK);
|
||||
furi_check(result);
|
||||
}
|
||||
|
||||
bool notify_pubsub(PubSub* pubsub, void* arg) {
|
||||
if(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK) {
|
||||
// iterate over subscribers
|
||||
list_pubsub_cb_it_t it;
|
||||
for(list_pubsub_cb_it(it, pubsub->items); !list_pubsub_cb_end_p(it);
|
||||
list_pubsub_cb_next(it)) {
|
||||
const PubSubItem* item = list_pubsub_cb_cref(it);
|
||||
item->cb(arg, item->ctx);
|
||||
}
|
||||
void furi_pubsub_publish(FuriPubSub* pubsub, void* message) {
|
||||
furi_check(osMutexAcquire(pubsub->mutex, osWaitForever) == osOK);
|
||||
|
||||
osMutexRelease(pubsub->mutex);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
// iterate over subscribers
|
||||
FuriPubSubSubscriptionList_it_t it;
|
||||
for(FuriPubSubSubscriptionList_it(it, pubsub->items); !FuriPubSubSubscriptionList_end_p(it);
|
||||
FuriPubSubSubscriptionList_next(it)) {
|
||||
const FuriPubSubSubscription* item = FuriPubSubSubscriptionList_cref(it);
|
||||
item->callback(message, item->callback_context);
|
||||
}
|
||||
|
||||
furi_check(osMutexRelease(pubsub->mutex) == osOK);
|
||||
}
|
||||
|
@@ -1,95 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "cmsis_os.h"
|
||||
#include "m-list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
== PubSub ==
|
||||
/** FuriPubSub Callback type */
|
||||
typedef void (*FuriPubSubCallback)(const void* message, void* context);
|
||||
|
||||
* PubSub allows users to subscribe on notifies and notify subscribers.
|
||||
* Notifier side can pass `void*` arg to subscriber callback,
|
||||
* and also subscriber can set `void*` context pointer that pass into
|
||||
* callback (you can see callback signature below).
|
||||
/** FuriPubSub type */
|
||||
typedef struct FuriPubSub FuriPubSub;
|
||||
|
||||
/** FuriPubSubSubscription type */
|
||||
typedef struct FuriPubSubSubscription FuriPubSubSubscription;
|
||||
|
||||
/** Allocate FuriPubSub
|
||||
*
|
||||
* Reentrable, Not threadsafe, one owner
|
||||
*
|
||||
* @return pointer to FuriPubSub instance
|
||||
*/
|
||||
FuriPubSub* furi_pubsub_alloc();
|
||||
|
||||
typedef void (*PubSubCallback)(const void*, void*);
|
||||
typedef struct PubSubType PubSub;
|
||||
|
||||
typedef struct {
|
||||
PubSubCallback cb;
|
||||
void* ctx;
|
||||
PubSub* self;
|
||||
} PubSubItem;
|
||||
|
||||
LIST_DEF(list_pubsub_cb, PubSubItem, M_POD_OPLIST);
|
||||
|
||||
struct PubSubType {
|
||||
list_pubsub_cb_t items;
|
||||
osMutexId_t mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
* To create PubSub you should create PubSub instance and call `init_pubsub`.
|
||||
/** Free FuriPubSub
|
||||
*
|
||||
* @param pubsub FuriPubSub instance
|
||||
*/
|
||||
bool init_pubsub(PubSub* pubsub);
|
||||
void furi_pubsub_free(FuriPubSub* pubsub);
|
||||
|
||||
/**
|
||||
* Since we use dynamic memory - we must explicity delete pubsub
|
||||
/** Subscribe to FuriPubSub
|
||||
*
|
||||
* Threadsafe, Reentrable
|
||||
*
|
||||
* @param pubsub pointer to FuriPubSub instance
|
||||
* @param[in] callback The callback
|
||||
* @param callback_context The callback context
|
||||
*
|
||||
* @return pointer to FuriPubSubSubscription instance
|
||||
*/
|
||||
bool delete_pubsub(PubSub* pubsub);
|
||||
FuriPubSubSubscription*
|
||||
furi_pubsub_subscribe(FuriPubSub* pubsub, FuriPubSubCallback callback, void* callback_context);
|
||||
|
||||
/**
|
||||
* Use `subscribe_pubsub` to register your callback.
|
||||
/** Unsubscribe from FuriPubSub
|
||||
*
|
||||
* No use of `pubsub_subscription` allowed after call of this method
|
||||
* Threadsafe, Reentrable.
|
||||
*
|
||||
* @param pubsub pointer to FuriPubSub instance
|
||||
* @param pubsub_subscription pointer to FuriPubSubSubscription instance
|
||||
*/
|
||||
PubSubItem* subscribe_pubsub(PubSub* pubsub, PubSubCallback cb, void* ctx);
|
||||
void furi_pubsub_unsubscribe(FuriPubSub* pubsub, FuriPubSubSubscription* pubsub_subscription);
|
||||
|
||||
/**
|
||||
* Use `unsubscribe_pubsub` to unregister callback.
|
||||
/** Publish message to FuriPubSub
|
||||
*
|
||||
* Threadsafe, Reentrable.
|
||||
*
|
||||
* @param pubsub pointer to FuriPubSub instance
|
||||
* @param message message pointer to publish
|
||||
*/
|
||||
bool unsubscribe_pubsub(PubSubItem* pubsub_id);
|
||||
|
||||
/**
|
||||
* Use `notify_pubsub` to notify subscribers.
|
||||
*/
|
||||
bool notify_pubsub(PubSub* pubsub, void* arg);
|
||||
void furi_pubsub_publish(FuriPubSub* pubsub, void* message);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
```C
|
||||
// MANIFEST
|
||||
// name="test"
|
||||
// stack=128
|
||||
|
||||
void example_pubsub_handler(void* arg, void* ctx) {
|
||||
printf("get %d from %s\n", *(uint32_t*)arg, (const char*)ctx);
|
||||
}
|
||||
|
||||
void pubsub_test() {
|
||||
const char* app_name = "test app";
|
||||
|
||||
PubSub example_pubsub;
|
||||
init_pubsub(&example_pubsub);
|
||||
|
||||
if(!subscribe_pubsub(&example_pubsub, example_pubsub_handler, (void*)app_name)) {
|
||||
printf("critical error\n");
|
||||
flapp_exit(NULL);
|
||||
}
|
||||
|
||||
uint32_t counter = 0;
|
||||
while(1) {
|
||||
notify_pubsub(&example_pubsub, (void*)&counter);
|
||||
counter++;
|
||||
|
||||
osDelay(100);
|
||||
}
|
||||
}
|
||||
```
|
||||
*/
|
||||
|
@@ -84,8 +84,8 @@ bool furi_record_destroy(const char* name) {
|
||||
FuriRecordData* record_data = FuriRecordDataDict_get(furi_record->records, name_str);
|
||||
furi_assert(record_data);
|
||||
if(record_data->holders_count == 0) {
|
||||
FuriRecordDataDict_erase(furi_record->records, name_str);
|
||||
furi_check(osOK == osEventFlagsDelete(record_data->flags));
|
||||
FuriRecordDataDict_erase(furi_record->records, name_str);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,9 @@
|
||||
#include "check.h"
|
||||
#include "memmgr.h"
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
|
||||
#include <furi-hal.h>
|
||||
#include <m-dict.h>
|
||||
|
||||
|
Reference in New Issue
Block a user