LCOV - code coverage report
Current view: top level - drivers/usb/host/dwc_common_port - dwc_notifier.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 9 95 9.5 %
Date: 2020-09-30 20:25:01 Functions: 2 12 16.7 %
Branches: 2 62 3.2 %

           Branch data     Line data    Source code
       1                 :            : #ifdef DWC_NOTIFYLIB
       2                 :            : 
       3                 :            : #include "dwc_notifier.h"
       4                 :            : #include "dwc_list.h"
       5                 :            : 
       6                 :            : typedef struct dwc_observer {
       7                 :            :         void *observer;
       8                 :            :         dwc_notifier_callback_t callback;
       9                 :            :         void *data;
      10                 :            :         char *notification;
      11                 :            :         DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry;
      12                 :            : } observer_t;
      13                 :            : 
      14                 :            : DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer);
      15                 :            : 
      16                 :            : typedef struct dwc_notifier {
      17                 :            :         void *mem_ctx;
      18                 :            :         void *object;
      19                 :            :         struct observer_queue observers;
      20                 :            :         DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry;
      21                 :            : } notifier_t;
      22                 :            : 
      23                 :            : DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier);
      24                 :            : 
      25                 :            : typedef struct manager {
      26                 :            :         void *mem_ctx;
      27                 :            :         void *wkq_ctx;
      28                 :            :         dwc_workq_t *wq;
      29                 :            : //      dwc_mutex_t *mutex;
      30                 :            :         struct notifier_queue notifiers;
      31                 :            : } manager_t;
      32                 :            : 
      33                 :            : static manager_t *manager = NULL;
      34                 :            : 
      35                 :        404 : static int create_manager(void *mem_ctx, void *wkq_ctx)
      36                 :            : {
      37                 :        404 :         manager = dwc_alloc(mem_ctx, sizeof(manager_t));
      38         [ +  - ]:        404 :         if (!manager) {
      39                 :            :                 return -DWC_E_NO_MEMORY;
      40                 :            :         }
      41                 :            : 
      42                 :        404 :         DWC_CIRCLEQ_INIT(&manager->notifiers);
      43                 :            : 
      44                 :        404 :         manager->wq = dwc_workq_alloc(wkq_ctx, "DWC Notification WorkQ");
      45         [ +  - ]:        404 :         if (!manager->wq) {
      46                 :            :                 return -DWC_E_NO_MEMORY;
      47                 :            :         }
      48                 :            : 
      49                 :        404 :         return 0;
      50                 :            : }
      51                 :            : 
      52                 :          0 : static void free_manager(void)
      53                 :            : {
      54                 :          0 :         dwc_workq_free(manager->wq);
      55                 :            : 
      56                 :            :         /* All notifiers must have unregistered themselves before this module
      57                 :            :          * can be removed.  Hitting this assertion indicates a programmer
      58                 :            :          * error. */
      59                 :            :         DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers),
      60                 :            :                    "Notification manager being freed before all notifiers have been removed");
      61                 :          0 :         dwc_free(manager->mem_ctx, manager);
      62                 :          0 : }
      63                 :            : 
      64                 :            : #ifdef DEBUG
      65                 :            : static void dump_manager(void)
      66                 :            : {
      67                 :            :         notifier_t *n;
      68                 :            :         observer_t *o;
      69                 :            : 
      70                 :            :         DWC_ASSERT(manager, "Notification manager not found");
      71                 :            : 
      72                 :            :         DWC_DEBUG("List of all notifiers and observers:\n");
      73                 :            :         DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
      74                 :            :                 DWC_DEBUG("Notifier %p has observers:\n", n->object);
      75                 :            :                 DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) {
      76                 :            :                         DWC_DEBUG("    %p watching %s\n", o->observer, o->notification);
      77                 :            :                 }
      78                 :            :         }
      79                 :            : }
      80                 :            : #else
      81                 :            : #define dump_manager(...)
      82                 :            : #endif
      83                 :            : 
      84                 :            : static observer_t *alloc_observer(void *mem_ctx, void *observer, char *notification,
      85                 :            :                                   dwc_notifier_callback_t callback, void *data)
      86                 :            : {
      87                 :          0 :         observer_t *new_observer = dwc_alloc(mem_ctx, sizeof(observer_t));
      88                 :            : 
      89         [ #  # ]:          0 :         if (!new_observer) {
      90                 :            :                 return NULL;
      91                 :            :         }
      92                 :            : 
      93                 :          0 :         DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry);
      94                 :          0 :         new_observer->observer = observer;
      95                 :          0 :         new_observer->notification = notification;
      96                 :          0 :         new_observer->callback = callback;
      97                 :          0 :         new_observer->data = data;
      98                 :            :         return new_observer;
      99                 :            : }
     100                 :            : 
     101                 :            : static void free_observer(void *mem_ctx, observer_t *observer)
     102                 :            : {
     103                 :          0 :         dwc_free(mem_ctx, observer);
     104                 :            : }
     105                 :            : 
     106                 :          0 : static notifier_t *alloc_notifier(void *mem_ctx, void *object)
     107                 :            : {
     108                 :            :         notifier_t *notifier;
     109                 :            : 
     110         [ #  # ]:          0 :         if (!object) {
     111                 :            :                 return NULL;
     112                 :            :         }
     113                 :            : 
     114                 :          0 :         notifier = dwc_alloc(mem_ctx, sizeof(notifier_t));
     115         [ #  # ]:          0 :         if (!notifier) {
     116                 :            :                 return NULL;
     117                 :            :         }
     118                 :            : 
     119                 :          0 :         DWC_CIRCLEQ_INIT(&notifier->observers);
     120                 :          0 :         DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry);
     121                 :            : 
     122                 :          0 :         notifier->mem_ctx = mem_ctx;
     123                 :          0 :         notifier->object = object;
     124                 :          0 :         return notifier;
     125                 :            : }
     126                 :            : 
     127                 :          0 : static void free_notifier(notifier_t *notifier)
     128                 :            : {
     129                 :            :         observer_t *observer;
     130                 :            : 
     131         [ #  # ]:          0 :         DWC_CIRCLEQ_FOREACH(observer, &notifier->observers, list_entry) {
     132                 :            :                 free_observer(notifier->mem_ctx, observer);
     133                 :            :         }
     134                 :            : 
     135                 :          0 :         dwc_free(notifier->mem_ctx, notifier);
     136                 :          0 : }
     137                 :            : 
     138                 :            : static notifier_t *find_notifier(void *object)
     139                 :            : {
     140                 :            :         notifier_t *notifier;
     141                 :            : 
     142                 :            :         DWC_ASSERT(manager, "Notification manager not found");
     143                 :            : 
     144   [ #  #  #  # ]:          0 :         if (!object) {
     145                 :            :                 return NULL;
     146                 :            :         }
     147                 :            : 
     148   [ #  #  #  # ]:          0 :         DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) {
     149   [ #  #  #  # ]:          0 :                 if (notifier->object == object) {
     150                 :          0 :                         return notifier;
     151                 :            :                 }
     152                 :            :         }
     153                 :            : 
     154                 :            :         return NULL;
     155                 :            : }
     156                 :            : 
     157                 :        404 : int dwc_alloc_notification_manager(void *mem_ctx, void *wkq_ctx)
     158                 :            : {
     159                 :        404 :         return create_manager(mem_ctx, wkq_ctx);
     160                 :            : }
     161                 :            : 
     162                 :          0 : void dwc_free_notification_manager(void)
     163                 :            : {
     164                 :          0 :         free_manager();
     165                 :          0 : }
     166                 :            : 
     167                 :          0 : dwc_notifier_t *dwc_register_notifier(void *mem_ctx, void *object)
     168                 :            : {
     169                 :            :         notifier_t *notifier;
     170                 :            : 
     171                 :            :         DWC_ASSERT(manager, "Notification manager not found");
     172                 :            : 
     173                 :            :         notifier = find_notifier(object);
     174         [ #  # ]:          0 :         if (notifier) {
     175                 :          0 :                 DWC_ERROR("Notifier %p is already registered\n", object);
     176                 :          0 :                 return NULL;
     177                 :            :         }
     178                 :            : 
     179                 :          0 :         notifier = alloc_notifier(mem_ctx, object);
     180         [ #  # ]:          0 :         if (!notifier) {
     181                 :            :                 return NULL;
     182                 :            :         }
     183                 :            : 
     184         [ #  # ]:          0 :         DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry);
     185                 :            : 
     186                 :          0 :         DWC_INFO("Notifier %p registered", object);
     187                 :            :         dump_manager();
     188                 :            : 
     189                 :          0 :         return notifier;
     190                 :            : }
     191                 :            : 
     192                 :          0 : void dwc_unregister_notifier(dwc_notifier_t *notifier)
     193                 :            : {
     194                 :            :         DWC_ASSERT(manager, "Notification manager not found");
     195                 :            : 
     196         [ #  # ]:          0 :         if (!DWC_CIRCLEQ_EMPTY(&notifier->observers)) {
     197                 :            :                 observer_t *o;
     198                 :            : 
     199                 :          0 :                 DWC_ERROR("Notifier %p has active observers when removing\n", notifier->object);
     200         [ #  # ]:          0 :                 DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
     201                 :            :                         DWC_DEBUGC("    %p watching %s\n", o->observer, o->notification);
     202                 :            :                 }
     203                 :            : 
     204                 :            :                 DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&notifier->observers),
     205                 :            :                            "Notifier %p has active observers when removing", notifier);
     206                 :            :         }
     207                 :            : 
     208   [ #  #  #  # ]:          0 :         DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry);
     209                 :          0 :         free_notifier(notifier);
     210                 :            : 
     211                 :          0 :         DWC_INFO("Notifier unregistered");
     212                 :            :         dump_manager();
     213                 :          0 : }
     214                 :            : 
     215                 :            : /* Add an observer to observe the notifier for a particular state, event, or notification. */
     216                 :          0 : int dwc_add_observer(void *observer, void *object, char *notification,
     217                 :            :                      dwc_notifier_callback_t callback, void *data)
     218                 :            : {
     219                 :            :         notifier_t *notifier = find_notifier(object);
     220                 :            :         observer_t *new_observer;
     221                 :            : 
     222         [ #  # ]:          0 :         if (!notifier) {
     223                 :          0 :                 DWC_ERROR("Notifier %p is not found when adding observer\n", object);
     224                 :          0 :                 return -DWC_E_INVALID;
     225                 :            :         }
     226                 :            : 
     227                 :            :         new_observer = alloc_observer(notifier->mem_ctx, observer, notification, callback, data);
     228         [ #  # ]:          0 :         if (!new_observer) {
     229                 :            :                 return -DWC_E_NO_MEMORY;
     230                 :            :         }
     231                 :            : 
     232         [ #  # ]:          0 :         DWC_CIRCLEQ_INSERT_TAIL(&notifier->observers, new_observer, list_entry);
     233                 :            : 
     234                 :          0 :         DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p",
     235                 :            :                  observer, object, notification, callback, data);
     236                 :            : 
     237                 :            :         dump_manager();
     238                 :          0 :         return 0;
     239                 :            : }
     240                 :            : 
     241                 :          0 : int dwc_remove_observer(void *observer)
     242                 :            : {
     243                 :            :         notifier_t *n;
     244                 :            : 
     245                 :            :         DWC_ASSERT(manager, "Notification manager not found");
     246                 :            : 
     247         [ #  # ]:          0 :         DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) {
     248                 :            :                 observer_t *o;
     249                 :            :                 observer_t *o2;
     250                 :            : 
     251         [ #  # ]:          0 :                 DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) {
     252         [ #  # ]:          0 :                         if (o->observer == observer) {
     253   [ #  #  #  # ]:          0 :                                 DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry);
     254                 :          0 :                                 DWC_INFO("Removing observer %p from notifier %p watching notification %s:",
     255                 :            :                                          o->observer, n->object, o->notification);
     256                 :            :                                 free_observer(n->mem_ctx, o);
     257                 :            :                         }
     258                 :            :                 }
     259                 :            :         }
     260                 :            : 
     261                 :            :         dump_manager();
     262                 :          0 :         return 0;
     263                 :            : }
     264                 :            : 
     265                 :            : typedef struct callback_data {
     266                 :            :         void *mem_ctx;
     267                 :            :         dwc_notifier_callback_t cb;
     268                 :            :         void *observer;
     269                 :            :         void *data;
     270                 :            :         void *object;
     271                 :            :         char *notification;
     272                 :            :         void *notification_data;
     273                 :            : } cb_data_t;
     274                 :            : 
     275                 :          0 : static void cb_task(void *data)
     276                 :            : {
     277                 :            :         cb_data_t *cb = (cb_data_t *)data;
     278                 :            : 
     279                 :          0 :         cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data);
     280                 :          0 :         dwc_free(cb->mem_ctx, cb);
     281                 :          0 : }
     282                 :            : 
     283                 :          0 : void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data)
     284                 :            : {
     285                 :            :         observer_t *o;
     286                 :            : 
     287                 :            :         DWC_ASSERT(manager, "Notification manager not found");
     288                 :            : 
     289         [ #  # ]:          0 :         DWC_CIRCLEQ_FOREACH(o, &notifier->observers, list_entry) {
     290                 :          0 :                 int len = DWC_STRLEN(notification);
     291                 :            : 
     292         [ #  # ]:          0 :                 if (DWC_STRLEN(o->notification) != len) {
     293                 :          0 :                         continue;
     294                 :            :                 }
     295                 :            : 
     296         [ #  # ]:          0 :                 if (DWC_STRNCMP(o->notification, notification, len) == 0) {
     297                 :          0 :                         cb_data_t *cb_data = dwc_alloc(notifier->mem_ctx, sizeof(cb_data_t));
     298                 :            : 
     299         [ #  # ]:          0 :                         if (!cb_data) {
     300                 :          0 :                                 DWC_ERROR("Failed to allocate callback data\n");
     301                 :          0 :                                 return;
     302                 :            :                         }
     303                 :            : 
     304                 :          0 :                         cb_data->mem_ctx = notifier->mem_ctx;
     305                 :          0 :                         cb_data->cb = o->callback;
     306                 :          0 :                         cb_data->observer = o->observer;
     307                 :          0 :                         cb_data->data = o->data;
     308                 :          0 :                         cb_data->object = notifier->object;
     309                 :          0 :                         cb_data->notification = notification;
     310                 :          0 :                         cb_data->notification_data = notification_data;
     311                 :            :                         DWC_DEBUGC("Observer found %p for notification %s\n", o->observer, notification);
     312                 :          0 :                         DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data,
     313                 :            :                                            "Notify callback from %p for Notification %s, to observer %p",
     314                 :            :                                            cb_data->object, notification, cb_data->observer);
     315                 :            :                 }
     316                 :            :         }
     317                 :            : }
     318                 :            : 
     319                 :            : #endif  /* DWC_NOTIFYLIB */

Generated by: LCOV version 1.14