You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by cl...@apache.org on 2021/10/29 07:38:39 UTC

[qpid-proton] branch main updated: PROTON-2422: fix epoll timer ordering bug

This is an automated email from the ASF dual-hosted git repository.

cliffjansen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git


The following commit(s) were added to refs/heads/main by this push:
     new 63abb68  PROTON-2422: fix epoll timer ordering bug
63abb68 is described below

commit 63abb683de7dcc5ded69c2e095fae68e14e9d463
Author: Cliff Jansen <cl...@apache.org>
AuthorDate: Fri Oct 29 00:35:14 2021 -0700

    PROTON-2422: fix epoll timer ordering bug
---
 c/src/proactor/epoll_timer.c | 54 +++++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 21 deletions(-)

diff --git a/c/src/proactor/epoll_timer.c b/c/src/proactor/epoll_timer.c
index 26de7d2..c154881 100644
--- a/c/src/proactor/epoll_timer.c
+++ b/c/src/proactor/epoll_timer.c
@@ -73,36 +73,48 @@ static void timerfd_drain(int fd) {
 
 // Struct to manage the ordering of timers on the heap ordered list and manage the lifecycle if
 // the parent timer is self-deleting.
+// This needs a Proton class definition to provide a custom compare() function.  It otherwise
+// remains private to this file and opts out of the general object machinery.
+// This works because the pn_list class is already meant to work with non-Proton objects using a
+// different compare operator (pn_void_compare).
 typedef struct timer_deadline_t {
   uint64_t list_deadline;      // Heap ordering deadline.  Must not change while on list.
   pni_timer_t *timer;          // Parent timer.  NULL means orphaned and to be deleted.
   bool resequenced;            // An out-of-order connection timeout caught and handled.
 } timer_deadline_t;
 
-static void timer_deadline_initialize(void *object) {
-  timer_deadline_t *td = (timer_deadline_t *) object;
-  memset(td, 0 , sizeof(*td));
-}
-
-static void timer_deadline_finalize(void *object) {
-  assert(((timer_deadline_t *) object)->list_deadline == 0);
-}
+static const pn_class_t *timer_deadline_reify(void *p);
 
+// The pn_list_t calls this to maintain its sorted heap.
 static intptr_t timer_deadline_compare(void *oa, void *ob) {
   timer_deadline_t *a = (timer_deadline_t *) oa;
   timer_deadline_t *b = (timer_deadline_t *) ob;
   return a->list_deadline - b->list_deadline;
 }
 
-#define timer_deadline_inspect NULL
-#define timer_deadline_hashcode NULL
 #define CID_timer_deadline CID_pn_void
+#define timer_deadline_new NULL
+#define timer_deadline_initialize NULL
+#define timer_deadline_incref pn_void_incref
+#define timer_deadline_decref pn_void_decref
+#define timer_deadline_refcount pn_void_refcount
+#define timer_deadline_finalize NULL
+#define timer_deadline_free NULL
+#define timer_deadline_hashcode NULL
+#define timer_deadline_inspect NULL
 
-static timer_deadline_t* pni_timer_deadline(void) {
-  static const pn_class_t timer_deadline_clazz = PN_CLASS(timer_deadline);
-  return (timer_deadline_t *) pn_class_new(&timer_deadline_clazz, sizeof(timer_deadline_t));
+static const pn_class_t timer_deadline_clazz = PN_METACLASS(timer_deadline);
+static const pn_class_t *timer_deadline_reify(void *p) { return &timer_deadline_clazz; }
+
+static timer_deadline_t* timer_deadline_t_new(void) {
+  // Just the struct.  Not a Proton class based object.
+  return (timer_deadline_t *) calloc(1, sizeof(timer_deadline_t));
 }
 
+static void timer_deadline_t_free(timer_deadline_t* td) {
+  assert(td->list_deadline == 0);
+  free(td);
+}
 
 struct pni_timer_t {
   uint64_t deadline;
@@ -119,7 +131,7 @@ pni_timer_t *pni_timer(pni_timer_manager_t *tm, pconnection_t *c) {
   if (!timer) return NULL;
   if (c) {
     // Connections are tracked on the timer_heap.  Allocate the tracking struct.
-    td = pni_timer_deadline();
+    td = timer_deadline_t_new();
     if (!td) {
       free(timer);
       return NULL;
@@ -147,14 +159,14 @@ void pni_timer_free(pni_timer_t *timer) {
   lock(&tm->deletion_mutex);
   if (td) {
     if (td->list_deadline)
-      td->timer = NULL;  // Orphan.  timer_manager does eventual pn_free() in process().
+      td->timer = NULL;  // Orphan.  timer_manager does eventual timer_deadline_t_free() in process().
     else
       can_free_td = true;
   }
   unlock(&tm->deletion_mutex);
   unlock(&tm->task.mutex);
   if (can_free_td) {
-    pn_free(td);
+    timer_deadline_t_free(td);
   }
   free(timer);
 }
@@ -171,8 +183,8 @@ bool pni_timer_manager_init(pni_timer_manager_t *tm) {
   task_init(&tm->task, TIMER_MANAGER, p);
   pmutex_init(&tm->deletion_mutex);
 
-  // PN_VOID turns off ref counting for the elements in the list.
-  tm->timers_heap = pn_list(PN_VOID, 0);
+  // Heap sorted pn_list_t using timer_deadline_compare() to determine ordering.
+  tm->timers_heap = pn_list(&timer_deadline_clazz, 0);
   if (!tm->timers_heap)
     return false;
   tm->proactor_timer = pni_timer(tm, NULL);
@@ -200,7 +212,7 @@ void pni_timer_manager_finalize(pni_timer_manager_t *tm) {
     for (size_t idx = 0; idx < sz; idx++) {
       timer_deadline_t *td = (timer_deadline_t *) pn_list_get(tm->timers_heap, idx);
       td->list_deadline = 0;
-      pn_free(td);
+      timer_deadline_t_free(td);
     }
     pn_free(tm->timers_heap);
   }
@@ -322,7 +334,7 @@ pn_event_batch_t *pni_timer_manager_process(pni_timer_manager_t *tm, bool timeou
     //   timer freed -> free the associated timer_deadline popped off the list
     if (!td->timer) {
       unlock(&tm->task.mutex);
-      pn_free(td);
+      timer_deadline_t_free(td);
       lock(&tm->task.mutex);
     } else {
       uint64_t deadline = td->timer->deadline;
@@ -370,7 +382,7 @@ static timer_deadline_t *replace_timer_deadline(pni_timer_manager_t *tm, pni_tim
 
   unlock(&tm->task.mutex);
   // Create replacement timer for life of connection.
-  timer_deadline_t *new_td = pni_timer_deadline();
+  timer_deadline_t *new_td = timer_deadline_t_new();
   if (!new_td)
     EPOLL_FATAL("replacement timer deadline allocation", errno);
   lock(&tm->task.mutex);

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org