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:
Anna Prosvetova
2021-11-01 23:35:54 +03:00
committed by GitHub
parent b397442d89
commit e9e76e144c
37 changed files with 350 additions and 214 deletions

View File

@@ -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);
}

View File

@@ -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);
}
}
```
*/

View File

@@ -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;
}

View File

@@ -2,6 +2,9 @@
#include "check.h"
#include "memmgr.h"
#include <FreeRTOS.h>
#include <task.h>
#include <furi-hal.h>
#include <m-dict.h>