Skip to content

Commit

Permalink
lwip: add mbox sync testcase
Browse files Browse the repository at this point in the history
The commit played the issue reported to
Samsung#5380. The patch should pass
the testcase in mbox_sync.c
  • Loading branch information
pillip8282 committed Jan 4, 2022
1 parent 1d44986 commit b0ce1cc
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 7 deletions.
17 changes: 10 additions & 7 deletions os/net/lwip/test/unit/mbox/mbox_shared.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static sem_t *g_signal_ctob = NULL;
void mbox_shared_event1(void)
{
printf("[EVT] let task C know mbox is empty \t%s:%d\n", __FUNCTION__,
__LINE__);
__LINE__);
sem_post(g_signal_atoc);
}

Expand Down Expand Up @@ -109,7 +109,7 @@ static void *a_thread(void *arg)
while (recv_cnt < QUEUE_MSG_CNT) {
lwip_msg_s *msg = NULL;
printf("[taskA] -->sys_arch_mbox_fetch \t%s:%d\n", __FUNCTION__,
__LINE__);
__LINE__);
uint32_t res = sys_arch_mbox_fetch(&g_tcpmbox, (void **)&msg, 0);
if (res != 0) {
assert(0);
Expand Down Expand Up @@ -138,7 +138,7 @@ static void *b_thread(void *arg)
return NULL;
}

static int _init_resource(void)
static void _init_resource(void)
{
ST_ASSERT_EQ(ERR_OK, sys_mbox_new(&g_tcpmbox, TCP_QUEUE_SIZE));
printf("[TEST] mbox created %p %d\n", &g_tcpmbox, TCP_QUEUE_SIZE);
Expand All @@ -157,7 +157,7 @@ static int _init_resource(void)
ST_ASSERT_EQ(0, sem_init(g_signal_ctob, 0, 0));
}

static int _deinit_resource(void)
static void _deinit_resource(void)
{
ST_ASSERT_EQ(0, sem_destroy(g_signal_atoc));
ST_ASSERT_EQ(0, sem_destroy(g_signal_ctoa));
Expand All @@ -177,9 +177,11 @@ static void _print_result(void)

int shared_test(void)
{
pthread_t contid, taid, tbid;
pthread_t contid;
pthread_t taid;
pthread_t tbid;

(void)_init_resource();
_init_resource();

ST_ASSERT_EQ(0, pthread_create(&contid, NULL, control_thread, NULL));
ST_ASSERT_EQ(0, pthread_create(&taid, NULL, a_thread, NULL));
Expand All @@ -190,5 +192,6 @@ int shared_test(void)
pthread_join(tbid, NULL);

_print_result();
(void)_deinit_resource();
_deinit_resource();
return 0;
}
224 changes: 224 additions & 0 deletions os/net/lwip/test/unit/mbox/mbox_sync.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/****************************************************************************
*
* Copyright 2022 Samsung Electronics All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************/
#include <assert.h>
#include <pthread.h>
#include <queue.h>
#include <semaphore.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stress_tool/st_perf.h>
#include <sys/types.h>
#include <unistd.h>

#include "mbox_util.h"
#include "port/port.h"
#include "sys_arch.h"

#define TCP_QUEUE_SIZE 50
#define QUEUE_MSG_CNT 100
#define FETCH_TIMEOUT 30000 // 30ms

static sys_mbox_t g_tcpmbox;
static sem_t *g_signal_atoc = NULL;
static sem_t *g_signal_ctoa = NULL;
static sem_t *g_signal_btoc = NULL;
static sem_t *g_signal_ctob = NULL;

void mbox_sync_event1(void)
{
printf("[EVT] task A call wait not_empty signal \t%s:%d\n", __FUNCTION__,
__LINE__);
}

void mbox_sync_event2(uint32_t res)
{
printf("[EVT] res %x %x \t%s:%d\n", res, SYS_ARCH_TIMEOUT, __FUNCTION__,
__LINE__);
if (res != SYS_ARCH_TIMEOUT && (g_tcpmbox.front == g_tcpmbox.rear)) {
/* if result is not timeout while mbox is empty then it receives invalid
* event */
printf("[EVT] receive invalid signal %d %d\t%s:%d\n", res, SYS_ARCH_TIMEOUT,
__FUNCTION__, __LINE__);
assert(0);
}

printf(
"[EVT] let control task know that timeout happened int task A "
"\t%s:%d\n",
__FUNCTION__, __LINE__);
printf("[EVT] wait_fetch %d \t%s:%d\n", g_tcpmbox.wait_fetch, __FUNCTION__,
__LINE__);
sem_post(g_signal_atoc);
sem_wait(g_signal_ctoa);
}

void mbox_sync_event3(void)
{
printf(
"[EVT] there is no task waiting not_empty signal. \t%s:%d\n",
__FUNCTION__, __LINE__);
printf(
"[EVT] However task b "
"generates additional signal which mess up event handler \t%s:%d\n",
__FUNCTION__, __LINE__);
sem_post(g_signal_btoc);
}

void mbox_sync_event4(void)
{
if (g_tcpmbox.front == ((g_tcpmbox.rear + 1) % g_tcpmbox.queue_size)) {
printf("[EVT] receive invalid signal in posting\t%s:%d\n",
__FUNCTION__, __LINE__);
printf("[EVT] (queue is still full \t%s:%d\n", __FUNCTION__, __LINE__);
assert(0);
}
}

static void *control_thread(void *arg)
{
/* 1) Task A tried to fetch an data from mbox with timeout
2) If mbox is empty then Task A increase wait_fetch with mutex protection
3) Task A releases mutex and sys_arch_sem_wait(mail, timeout) to get an event.
4) Time expires and task A exit from sys_arch_sem_wait()
5) Context switching occurs, Task B post event with sys_arch_mbox_post()
6) After task B enque data to mbox, it'll check whether send an event or not
7) Task B sends an event because mbox was empty(first_msg == 1) and wait_fetch
is not 0.
8) After context switching task A lock mutex and decrease wait_fetch
and exit the function.
9) No task receive the event task B sent, so unexpected
behavior can be happened. */

/* send signal to task a to call sys_arch_mbox_fetch */
printf("[COND] let task A fetch the event \t%s:%d\n", __FUNCTION__, __LINE__);
sem_post(g_signal_ctoa);
/* wait event that task a wait event with mbox->mail because it's empty */
printf("[COND] wait timeout signal \t%s:%d\n", __FUNCTION__, __LINE__);
sem_wait(g_signal_atoc);
printf("[COND] task A timeout happened \t%s:%d\n", __FUNCTION__, __LINE__);

/* let task b to post data until g_tcpmbox is full */
printf("[COND] let task B to generate invalid signal \t%s:%d\n", __FUNCTION__,
__LINE__);
sem_post(g_signal_ctob);

printf("[COND] after task B generates signal, wake up task A \t%s:%d\n",
__FUNCTION__, __LINE__);
sem_wait(g_signal_btoc);

/* after invalid signal generated then wake up task a */
sem_wait(g_signal_ctoa);
return NULL;
}

static void *a_thread(void *arg)
{
uint32_t recv_cnt = 0;
printf("[taskA] wait control signal \t%s:%d\n", __FUNCTION__, __LINE__);
sem_wait(g_signal_ctoa);
while (recv_cnt < QUEUE_MSG_CNT) {
lwip_msg_s *msg = NULL;
printf("[taskA] -->sys_arch_mbox_fetch timeout %d\t%s:%d\n", FETCH_TIMEOUT,
__FUNCTION__, __LINE__);
uint32_t res =
sys_arch_mbox_fetch(&g_tcpmbox, (void **)&msg, FETCH_TIMEOUT);
if (res != 0) {
assert(0);
}
free(msg);
recv_cnt++;
}
return NULL;
}

static void *b_thread(void *arg)
{
printf("[taskB] wait control signal \t%s:%d\n", __FUNCTION__, __LINE__);
sem_wait(g_signal_ctob);
uint32_t send_cnt = 0;
while (send_cnt < QUEUE_MSG_CNT) {
lwip_msg_s *msg = (lwip_msg_s *)malloc(sizeof(lwip_msg_s));
if (!msg) {
assert(0);
}
msg->type = APP_MSG;
msg->data = send_cnt + 1000;
sys_mbox_post(&g_tcpmbox, (void *)msg);
send_cnt++;
}
return NULL;
}

static void _init_resource(void)
{
ST_ASSERT_EQ(ERR_OK, sys_mbox_new(&g_tcpmbox, TCP_QUEUE_SIZE));
printf("[TEST] mbox created %p %d\n", &g_tcpmbox, TCP_QUEUE_SIZE);
g_signal_atoc = (sem_t *)malloc(sizeof(sem_t));
ST_ASSERT_NEQ(NULL, g_signal_atoc);
g_signal_ctoa = (sem_t *)malloc(sizeof(sem_t));
ST_ASSERT_NEQ(NULL, g_signal_ctoa);
g_signal_btoc = (sem_t *)malloc(sizeof(sem_t));
ST_ASSERT_NEQ(NULL, g_signal_btoc);
g_signal_ctob = (sem_t *)malloc(sizeof(sem_t));
ST_ASSERT_NEQ(NULL, g_signal_ctob);

ST_ASSERT_EQ(0, sem_init(g_signal_atoc, 0, 0));
ST_ASSERT_EQ(0, sem_init(g_signal_ctoa, 0, 0));
ST_ASSERT_EQ(0, sem_init(g_signal_btoc, 0, 0));
ST_ASSERT_EQ(0, sem_init(g_signal_ctob, 0, 0));
}

static void _deinit_resource(void)
{
ST_ASSERT_EQ(0, sem_destroy(g_signal_atoc));
ST_ASSERT_EQ(0, sem_destroy(g_signal_ctoa));
ST_ASSERT_EQ(0, sem_destroy(g_signal_btoc));
ST_ASSERT_EQ(0, sem_destroy(g_signal_ctob));

free(g_signal_atoc);
free(g_signal_ctoa);
free(g_signal_btoc);
free(g_signal_ctob);
}

static void _print_result(void)
{
printf("[TEST] test done\n");
}

int sync_test(void)
{
pthread_t contid;
pthread_t taid;
pthread_t tbid;

_init_resource();

ST_ASSERT_EQ(0, pthread_create(&contid, NULL, control_thread, NULL));
ST_ASSERT_EQ(0, pthread_create(&taid, NULL, a_thread, NULL));
ST_ASSERT_EQ(0, pthread_create(&tbid, NULL, b_thread, NULL));

pthread_join(contid, NULL);
pthread_join(taid, NULL);
pthread_join(tbid, NULL);

_print_result();
_deinit_resource();
return 0;
}

0 comments on commit b0ce1cc

Please sign in to comment.