From acfdc588af088dda6c61b01bab9a24832a7e41e1 Mon Sep 17 00:00:00 2001 From: Maciej Bocianski Date: Tue, 4 Feb 2020 16:20:35 +0100 Subject: [PATCH 1/5] equeue: skip equeue_incid call for user allocated events while dispatching User allocaded events doesn't utilize id field in a way that normal event does, so we shouldn't call equeue_incid on it --- events/source/equeue.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/events/source/equeue.c b/events/source/equeue.c index d6229b1eba3..b562b91f8c4 100644 --- a/events/source/equeue.c +++ b/events/source/equeue.c @@ -506,7 +506,9 @@ void equeue_dispatch(equeue_t *q, int ms) e->target += e->period; equeue_enqueue(q, e, equeue_tick()); } else { - equeue_incid(q, e); + if (!EQUEUE_IS_USER_ALLOCATED_EVENT(e)) { + equeue_incid(q, e); + } equeue_dealloc(q, e + 1); } } From b4fac7132588069b102d38824a9b6eecc8055f44 Mon Sep 17 00:00:00 2001 From: Maciej Bocianski Date: Fri, 24 Jan 2020 12:33:17 +0100 Subject: [PATCH 2/5] user allocated events: fix event cancelling for user allocated events use id for event state tracking skip event canceling when already canceled or dispatched --- events/UserAllocatedEvent.h | 2 +- events/source/equeue.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/events/UserAllocatedEvent.h b/events/UserAllocatedEvent.h index 26a2b5b90c7..a9544798e6e 100644 --- a/events/UserAllocatedEvent.h +++ b/events/UserAllocatedEvent.h @@ -243,7 +243,7 @@ class UserAllocatedEvent { */ bool cancel() { - return equeue_cancel_user_allocated(_equeue, &_e); + return _post_ref > 0 ? equeue_cancel_user_allocated(_equeue, &_e) : false; } diff --git a/events/source/equeue.c b/events/source/equeue.c index b562b91f8c4..d45f9c25010 100644 --- a/events/source/equeue.c +++ b/events/source/equeue.c @@ -24,6 +24,12 @@ // check if the event is allocaded by user - event address is outside queues internal buffer address range #define EQUEUE_IS_USER_ALLOCATED_EVENT(e) ((q->buffer == NULL) || ((uintptr_t)(e) < (uintptr_t)q->buffer) || ((uintptr_t)(e) > ((uintptr_t)q->slab.data))) +// for user allocated events use event id to track event state +enum { + EQUEUE_USER_ALLOCATED_EVENT_STATE_INPROGRESS = 1, + EQUEUE_USER_ALLOCATED_EVENT_STATE_DONE = 0 // event canceled or dispatching done +}; + // calculate the relative-difference between absolute times while // correctly handling overflow conditions static inline int equeue_tickdiff(unsigned a, unsigned b) @@ -229,7 +235,9 @@ void equeue_dealloc(equeue_t *q, void *p) e->dtor(e + 1); } - if (!EQUEUE_IS_USER_ALLOCATED_EVENT(e)) { + if (EQUEUE_IS_USER_ALLOCATED_EVENT(e)) { + e->id = EQUEUE_USER_ALLOCATED_EVENT_STATE_DONE; + } else { equeue_mem_dealloc(q, e); } } @@ -402,6 +410,7 @@ void equeue_post_user_allocated(equeue_t *q, void (*cb)(void *), void *p) unsigned tick = equeue_tick(); e->cb = cb; e->target = tick + e->target; + e->id = EQUEUE_USER_ALLOCATED_EVENT_STATE_INPROGRESS; equeue_enqueue(q, e, tick); equeue_sema_signal(&q->eventsema); @@ -424,7 +433,7 @@ bool equeue_cancel(equeue_t *q, int id) bool equeue_cancel_user_allocated(equeue_t *q, void *e) { - if (!e) { + if (!e || ((struct equeue_event *)e)->id == EQUEUE_USER_ALLOCATED_EVENT_STATE_DONE) { return false; } From bc89974462ba3aaa991ebd1a74534e28ae289213 Mon Sep 17 00:00:00 2001 From: Maciej Bocianski Date: Fri, 24 Jan 2020 13:14:31 +0100 Subject: [PATCH 3/5] UserAllocatedEvent: set delay/period at event posting Event delay/period can be modified by equeue so it has to be reset at every post. --- events/UserAllocatedEvent.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/events/UserAllocatedEvent.h b/events/UserAllocatedEvent.h index a9544798e6e..94dd360b636 100644 --- a/events/UserAllocatedEvent.h +++ b/events/UserAllocatedEvent.h @@ -86,7 +86,7 @@ class UserAllocatedEvent { * @param f Function to execute when the event is dispatched * @param args Arguments to bind to the callback */ - constexpr UserAllocatedEvent(F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _equeue(), _post_ref() + constexpr UserAllocatedEvent(F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _delay(), _period(-1), _equeue(), _post_ref() { } @@ -100,7 +100,7 @@ class UserAllocatedEvent { * @param f Function to execute when the event is dispatched * @param args Arguments to bind to the callback */ - constexpr UserAllocatedEvent(EventQueue *queue, F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _equeue(&queue->_equeue), _post_ref() + constexpr UserAllocatedEvent(EventQueue *queue, F f, ArgTs... args) : _e(get_default_equeue_event()), _c(f, args...), _delay(), _period(-1), _equeue(&queue->_equeue), _post_ref() { } @@ -215,7 +215,7 @@ class UserAllocatedEvent { void delay(int delay) { MBED_ASSERT(!_post_ref); - equeue_event_delay(&_e + 1, delay); + _delay = delay; } /** Configure the period of an event @@ -225,7 +225,7 @@ class UserAllocatedEvent { void period(int period) { MBED_ASSERT(!_post_ref); - equeue_event_period(&_e + 1, period); + _period = period; } /** Cancels posted event @@ -251,6 +251,8 @@ class UserAllocatedEvent { friend class EventQueue; struct equeue_event _e; C _c; + int _delay; + int _period; struct equeue *_equeue; uint8_t _post_ref; @@ -260,17 +262,22 @@ class UserAllocatedEvent { return false; } core_util_atomic_incr_u8(&_post_ref, 1); + equeue_event_delay(&_e + 1, _delay); + equeue_event_period(&_e + 1, _period); equeue_post_user_allocated(_equeue, &EventQueue::function_call, &_e); return true; } bool post_on(EventQueue *queue) { + MBED_ASSERT(queue); if (_post_ref) { return false; } _equeue = &(queue->_equeue); core_util_atomic_incr_u8(&_post_ref, 1); + equeue_event_delay(&_e + 1, _delay); + equeue_event_period(&_e + 1, _period); equeue_post_user_allocated(_equeue, &EventQueue::function_call, &_e); return true; } From 784393a9192a191912cddc534ef7a089a9175935 Mon Sep 17 00:00:00 2001 From: Maciej Bocianski Date: Fri, 24 Jan 2020 15:06:38 +0100 Subject: [PATCH 4/5] equeue tests update - test periodic user allocated events - test user allocated events re-posting - test unnecessary cancels of user allocated events --- TESTS/events/equeue/main.cpp | 28 +++++++++++--------- UNITTESTS/events/equeue/test_equeue.cpp | 34 ++++++++++++++----------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/TESTS/events/equeue/main.cpp b/TESTS/events/equeue/main.cpp index 17edc3cc364..061b2d9e41e 100644 --- a/TESTS/events/equeue/main.cpp +++ b/TESTS/events/equeue/main.cpp @@ -1003,14 +1003,14 @@ static void test_equeue_user_allocated_event_post() uint8_t touched = 0; user_allocated_event e1 = { { 0, 0, 0, NULL, NULL, NULL, 0, -1, NULL, NULL }, 0 }; - user_allocated_event e2 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - user_allocated_event e3 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - user_allocated_event e4 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; + user_allocated_event e2 = { { 0, 0, 0, NULL, NULL, NULL, 10, 10, NULL, NULL }, 0 }; + user_allocated_event e3 = { { 0, 0, 0, NULL, NULL, NULL, 10, 10, NULL, NULL }, 0 }; + user_allocated_event e4 = { { 0, 0, 0, NULL, NULL, NULL, 10, 10, NULL, NULL }, 0 }; user_allocated_event e5 = { { 0, 0, 0, NULL, NULL, NULL, 0, -1, NULL, NULL }, 0 }; - TEST_ASSERT_NOT_EQUAL(0, equeue_call(&q, simple_func, &touched)); - TEST_ASSERT_EQUAL_INT(0, equeue_call(&q, simple_func, &touched)); - TEST_ASSERT_EQUAL_INT(0, equeue_call(&q, simple_func, &touched)); + TEST_ASSERT_NOT_EQUAL(0, equeue_call_every(&q, 10, simple_func, &touched)); + TEST_ASSERT_EQUAL_INT(0, equeue_call_every(&q, 10, simple_func, &touched)); + TEST_ASSERT_EQUAL_INT(0, equeue_call_every(&q, 10, simple_func, &touched)); equeue_post_user_allocated(&q, simple_func, &e1.e); equeue_post_user_allocated(&q, simple_func, &e2.e); @@ -1018,8 +1018,9 @@ static void test_equeue_user_allocated_event_post() equeue_post_user_allocated(&q, simple_func, &e4.e); equeue_post_user_allocated(&q, simple_func, &e5.e); equeue_cancel_user_allocated(&q, &e3.e); + equeue_cancel_user_allocated(&q, &e3.e); - equeue_dispatch(&q, 1); + equeue_dispatch(&q, 11); TEST_ASSERT_EQUAL_UINT8(1, touched); TEST_ASSERT_EQUAL_UINT8(1, e1.touched); @@ -1028,13 +1029,16 @@ static void test_equeue_user_allocated_event_post() TEST_ASSERT_EQUAL_UINT8(1, e4.touched); TEST_ASSERT_EQUAL_UINT8(1, e5.touched); - equeue_dispatch(&q, 10); + e3.e.target = 10; // set target as it's modified by equeue_call + e3.e.period = 10; // set period as it's reset by equeue_cancel + equeue_post_user_allocated(&q, simple_func, &e3.e); + equeue_dispatch(&q, 101); - TEST_ASSERT_EQUAL_UINT8(1, touched); + TEST_ASSERT_EQUAL_UINT8(11, touched); TEST_ASSERT_EQUAL_UINT8(1, e1.touched); - TEST_ASSERT_EQUAL_UINT8(1, e2.touched); - TEST_ASSERT_EQUAL_UINT8(0, e3.touched); - TEST_ASSERT_EQUAL_UINT8(1, e4.touched); + TEST_ASSERT_EQUAL_UINT8(11, e2.touched); + TEST_ASSERT_EQUAL_UINT8(10, e3.touched); + TEST_ASSERT_EQUAL_UINT8(11, e4.touched); TEST_ASSERT_EQUAL_UINT8(1, e5.touched); equeue_destroy(&q); diff --git a/UNITTESTS/events/equeue/test_equeue.cpp b/UNITTESTS/events/equeue/test_equeue.cpp index 599c59121b3..5d90023fda3 100644 --- a/UNITTESTS/events/equeue/test_equeue.cpp +++ b/UNITTESTS/events/equeue/test_equeue.cpp @@ -1072,14 +1072,14 @@ TEST_F(TestEqueue, test_equeue_user_allocated_event_post) uint8_t touched = 0; user_allocated_event e1 = { { 0, 0, 0, NULL, NULL, NULL, 0, -1, NULL, NULL }, 0 }; - user_allocated_event e2 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - user_allocated_event e3 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; - user_allocated_event e4 = { { 0, 0, 0, NULL, NULL, NULL, 1, -1, NULL, NULL }, 0 }; + user_allocated_event e2 = { { 0, 0, 0, NULL, NULL, NULL, 10, 10, NULL, NULL }, 0 }; + user_allocated_event e3 = { { 0, 0, 0, NULL, NULL, NULL, 10, 10, NULL, NULL }, 0 }; + user_allocated_event e4 = { { 0, 0, 0, NULL, NULL, NULL, 10, 10, NULL, NULL }, 0 }; user_allocated_event e5 = { { 0, 0, 0, NULL, NULL, NULL, 0, -1, NULL, NULL }, 0 }; - EXPECT_NE(0, equeue_call(&q, simple_func, &touched)); - EXPECT_EQ(0, equeue_call(&q, simple_func, &touched)); - EXPECT_EQ(0, equeue_call(&q, simple_func, &touched)); + EXPECT_NE(0, equeue_call_every(&q, 10, simple_func, &touched)); + EXPECT_EQ(0, equeue_call_every(&q, 10, simple_func, &touched)); + EXPECT_EQ(0, equeue_call_every(&q, 10, simple_func, &touched)); equeue_post_user_allocated(&q, simple_func, &e1.e); equeue_post_user_allocated(&q, simple_func, &e2.e); @@ -1087,8 +1087,9 @@ TEST_F(TestEqueue, test_equeue_user_allocated_event_post) equeue_post_user_allocated(&q, simple_func, &e4.e); equeue_post_user_allocated(&q, simple_func, &e5.e); equeue_cancel_user_allocated(&q, &e3.e); + equeue_cancel_user_allocated(&q, &e3.e); - equeue_dispatch(&q, 1); + equeue_dispatch(&q, 11); EXPECT_EQ(1, touched); EXPECT_EQ(1, e1.touched); @@ -1097,14 +1098,17 @@ TEST_F(TestEqueue, test_equeue_user_allocated_event_post) EXPECT_EQ(1, e4.touched); EXPECT_EQ(1, e5.touched); - equeue_dispatch(&q, 10); - - EXPECT_EQ(1, touched); - EXPECT_EQ(1, e1.touched); - EXPECT_EQ(1, e2.touched); - EXPECT_EQ(0, e3.touched); - EXPECT_EQ(1, e4.touched); - EXPECT_EQ(1, e5.touched); + e3.e.target = 10; // set target as it's modified by equeue_call + e3.e.period = 10; // set period as it's reset by equeue_cancel + equeue_post_user_allocated(&q, simple_func, &e3.e); + equeue_dispatch(&q, 101); + + EXPECT_EQ(11, touched); + EXPECT_EQ(1 , e1.touched); + EXPECT_EQ(11, e2.touched); + EXPECT_EQ(10 , e3.touched); + EXPECT_EQ(11, e4.touched); + EXPECT_EQ(1 , e5.touched); equeue_destroy(&q); } From 83a07836e4bb525e63dd2cdedfbfb189a641edc5 Mon Sep 17 00:00:00 2001 From: Maciej Bocianski Date: Tue, 28 Jan 2020 09:40:58 +0100 Subject: [PATCH 5/5] queue test update - extend mixed test with periodic events - improve static event queue test --- TESTS/events/queue/main.cpp | 73 ++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/TESTS/events/queue/main.cpp b/TESTS/events/queue/main.cpp index 3367622888c..130eb036d1e 100644 --- a/TESTS/events/queue/main.cpp +++ b/TESTS/events/queue/main.cpp @@ -362,14 +362,18 @@ void mixed_dynamic_static_events_queue_test() EventTest e1_test; Event e1 = queue.event(&e1_test, &EventTest::f0); + e1.delay(10); + e1.period(10); int id1 = e1.post(); TEST_ASSERT_NOT_EQUAL(0, id1); EventTest e2_test; Event e2 = queue.event(&e2_test, &EventTest::f1, 3); + e2.period(10); int id2 = e2.post(); TEST_ASSERT_NOT_EQUAL(0, id2); EventTest e3_test; Event e3 = queue.event(&e3_test, &EventTest::f5, 1, 2, 3, 4, 5); + e3.period(10); int id3 = e3.post(); TEST_ASSERT_NOT_EQUAL(0, id3); @@ -390,8 +394,11 @@ void mixed_dynamic_static_events_queue_test() TEST_ASSERT_EQUAL(false, ue0.try_call()); ue1.call_on(&queue); TEST_ASSERT_EQUAL(false, ue1.try_call()); + ue2.period(10); ue2.call_on(&queue); TEST_ASSERT_EQUAL(false, ue2.try_call()); + ue3.period(10); + ue3.delay(50); ue3.call_on(&queue); TEST_ASSERT_EQUAL(false, ue3.try_call()); ue4.call_on(&queue); @@ -400,21 +407,36 @@ void mixed_dynamic_static_events_queue_test() ue4.cancel(); e2.cancel(); - queue.dispatch(1); + queue.dispatch(101); TEST_ASSERT_EQUAL(true, touched); TEST_ASSERT_EQUAL(1, ue1_test.counter); - TEST_ASSERT_EQUAL(3, ue2_test.counter); - TEST_ASSERT_EQUAL(15, ue3_test.counter); + TEST_ASSERT_EQUAL(33, ue2_test.counter); + TEST_ASSERT_EQUAL(90, ue3_test.counter); TEST_ASSERT_EQUAL(0, ue4_test.counter); - TEST_ASSERT_EQUAL(1, e1_test.counter); + TEST_ASSERT_EQUAL(10, e1_test.counter); TEST_ASSERT_EQUAL(0, e2_test.counter); - TEST_ASSERT_EQUAL(15, e3_test.counter); + TEST_ASSERT_EQUAL(165, e3_test.counter); + + // user allocated event have to be canceled(removed from the queue) before destruction + // cancel all periodic user events + ue2.cancel(); + ue3.cancel(); } } static EventQueue g_queue(0); +static auto ue0 = g_queue.make_user_allocated_event(func0); +static EventTest test1; +static auto ue1 = make_user_allocated_event(&test1, &EventTest::f0); +static EventTest test2; +static auto ue2 = g_queue.make_user_allocated_event(&test2, &EventTest::f1, 3); +static EventTest test3; +static auto ue3 = make_user_allocated_event(&test3, &EventTest::f5, 1, 2, 3, 4, 5); +static EventTest test4; +static auto ue4 = g_queue.make_user_allocated_event(&test4, &EventTest::f5, 1, 2, 3, 4, 5); + /** Test that static queue executes user allocated events. * @@ -428,15 +450,20 @@ void static_events_queue_test() Event e0 = g_queue.event(func0); TEST_ASSERT_EQUAL(0, e0.post()); - auto ue0 = g_queue.make_user_allocated_event(func0); - EventTest test1; - auto ue1 = make_user_allocated_event(&test1, &EventTest::f0); - EventTest test2; - auto ue2 = g_queue.make_user_allocated_event(&test2, &EventTest::f1, 3); - EventTest test3; - auto ue3 = make_user_allocated_event(&test3, &EventTest::f5, 1, 2, 3, 4, 5); - EventTest test4; - auto ue4 = g_queue.make_user_allocated_event(&test4, &EventTest::f5, 1, 2, 3, 4, 5); + ue0.delay(100); + ue0.period(200); + + ue1.delay(100); + ue1.period(200); + + ue2.delay(100); + ue2.period(200); + + ue3.delay(100); + ue3.period(200); + + ue4.delay(100); + ue4.period(200); ue0.call(); TEST_ASSERT_EQUAL(false, ue0.try_call()); @@ -448,16 +475,26 @@ void static_events_queue_test() TEST_ASSERT_EQUAL(false, ue3.try_call()); ue4.call(); ue4.cancel(); + ue4.cancel(); TEST_ASSERT_EQUAL(true, ue4.try_call()); g_queue.cancel(&ue4); + g_queue.cancel(&ue4); - g_queue.dispatch(1); + g_queue.dispatch(400); - TEST_ASSERT_EQUAL(1, test1.counter); - TEST_ASSERT_EQUAL(3, test2.counter); - TEST_ASSERT_EQUAL(15, test3.counter); + TEST_ASSERT_EQUAL(2, test1.counter); + TEST_ASSERT_EQUAL(6, test2.counter); + TEST_ASSERT_EQUAL(30, test3.counter); TEST_ASSERT_EQUAL(0, test4.counter); + ue4.delay(1); + TEST_ASSERT_EQUAL(true, ue4.try_call()); + g_queue.dispatch(1); + + TEST_ASSERT_EQUAL(2, test1.counter); + TEST_ASSERT_EQUAL(6, test2.counter); + TEST_ASSERT_EQUAL(30, test3.counter); + TEST_ASSERT_EQUAL(15, test4.counter); } // Test setup