Message ID | 20221214213053.4174989-1-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | [v5] x86: Add a testcase for BZ #29863 | expand |
On Wed, Dec 14, 2022 at 1:30 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > When a thread is updating the memory area of memcmp and another thread > is doing memcmp, the memcmp return value is undefined. Add a testcase > to verify that memcmp won't segfault in this case. > --- > sysdeps/x86/Makefile | 8 +++ > sysdeps/x86/tst-memcmp-race.c | 106 ++++++++++++++++++++++++++++++++++ > 2 files changed, 114 insertions(+) > create mode 100644 sysdeps/x86/tst-memcmp-race.c > > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile > index 56fd5fc805..c3f05a06ab 100644 > --- a/sysdeps/x86/Makefile > +++ b/sysdeps/x86/Makefile > @@ -257,3 +257,11 @@ tests += \ > tests-static += \ > tst-sysconf-cache-linesize-static > endif > + > +ifeq ($(subdir),nptl) > +tests += \ > + tst-memcmp-race \ > +# tests > + > +CFLAGS-tst-memcmp-race.c += -O0 > +endif > diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c > new file mode 100644 > index 0000000000..eefa9e43c4 > --- /dev/null > +++ b/sysdeps/x86/tst-memcmp-race.c > @@ -0,0 +1,106 @@ > +/* Test case for memcmp with race condition. > + Copyright (C) 2022 Free Software Foundation, Inc. > + This file is part of the GNU C Library. > + > + The GNU C Library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + The GNU C Library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with the GNU C Library; if not, see > + <https://www.gnu.org/licenses/>. */ > + > +/* Verify that there is no segfault when one thread is updating the > + memory block of memcmp and the other thread is doing memcmp. */ > + > +#define TEST_MAIN > +#define TEST_NAME "memcmp" > + > +#include <stdio.h> > +#include <stdint.h> > +#include <string.h> > +#include <string/test-string.h> > +#include <support/xthread.h> > + > +#define NUM_THREADS 2 > +#define LOOP1 10000 > +#define LOOP2 1000000 > + > +typedef int (*proto_t) (const void *, const void *, size_t); > + > +IMPL (memcmp, 1) > + > +struct arg > +{ > + proto_t func; > + size_t len; > + int i; > +}; > + > +static void * > +childThread (void *tArgs) > +{ > + struct arg *a = (struct arg *) tArgs; > + int i; > + > + if (0 == a->i % 2) > + { > + for (i = 0; i < LOOP1; i++) > + { > + int result = a->func (buf1, buf2, a->len); So the test can catch more subtle errors can we test with memcmp args at begining and end of a page. i.e buf1/buf2 and (buf1 + page_size - a->len)/(buf2 + page_size - a->len). > + printf ("i = %d : result = %d\n", i, result); > + } > + } > + else > + { > + size_t offset = a->len > 16 ? a->len - 16 : 1; > + for (i = 0; i < LOOP2; i++) > + buf1[offset] = i & 1; > + } > + > + return NULL; > +} > + > +static void > +do_one_test (proto_t func, size_t len) > +{ > + int i; > + pthread_t threads[NUM_THREADS]; > + struct arg a[NUM_THREADS]; > + > + for (i = 0; i < NUM_THREADS; ++i) > + { > + a[i].func = func; > + a[i].len = len; > + a[i].i = i; > + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); > + } > + > + for (i = 0; i < NUM_THREADS; ++i) > + xpthread_join (threads[i]); > +} > + > +int > +test_main (void) > +{ > + test_init (); > + > + memset (buf1, 1, page_size); > + memset (buf2, 1, page_size); > + > + for (size_t i = 0; i <= 11; i++) > + { > + FOR_EACH_IMPL (impl, 0) > + do_one_test ((proto_t) impl->fn, (1 << i) + 1); can you also test 2^i - 1. > + } > + > + return 0; > +} > + > +#include <support/test-driver.c> > -- > 2.38.1 > Can you move this to the string directory (so we run this on all arch) and add corresponding tests for memcmpeq/wmemcmp.
On Mon, Dec 19, 2022 at 6:39 AM Noah Goldstein <goldstein.w.n@gmail.com> wrote: > > On Wed, Dec 14, 2022 at 1:30 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > When a thread is updating the memory area of memcmp and another thread > > is doing memcmp, the memcmp return value is undefined. Add a testcase > > to verify that memcmp won't segfault in this case. > > --- > > sysdeps/x86/Makefile | 8 +++ > > sysdeps/x86/tst-memcmp-race.c | 106 ++++++++++++++++++++++++++++++++++ > > 2 files changed, 114 insertions(+) > > create mode 100644 sysdeps/x86/tst-memcmp-race.c > > > > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile > > index 56fd5fc805..c3f05a06ab 100644 > > --- a/sysdeps/x86/Makefile > > +++ b/sysdeps/x86/Makefile > > @@ -257,3 +257,11 @@ tests += \ > > tests-static += \ > > tst-sysconf-cache-linesize-static > > endif > > + > > +ifeq ($(subdir),nptl) > > +tests += \ > > + tst-memcmp-race \ > > +# tests > > + > > +CFLAGS-tst-memcmp-race.c += -O0 > > +endif > > diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c > > new file mode 100644 > > index 0000000000..eefa9e43c4 > > --- /dev/null > > +++ b/sysdeps/x86/tst-memcmp-race.c > > @@ -0,0 +1,106 @@ > > +/* Test case for memcmp with race condition. > > + Copyright (C) 2022 Free Software Foundation, Inc. > > + This file is part of the GNU C Library. > > + > > + The GNU C Library is free software; you can redistribute it and/or > > + modify it under the terms of the GNU Lesser General Public > > + License as published by the Free Software Foundation; either > > + version 2.1 of the License, or (at your option) any later version. > > + > > + The GNU C Library is distributed in the hope that it will be useful, > > + but WITHOUT ANY WARRANTY; without even the implied warranty of > > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + Lesser General Public License for more details. > > + > > + You should have received a copy of the GNU Lesser General Public > > + License along with the GNU C Library; if not, see > > + <https://www.gnu.org/licenses/>. */ > > + > > +/* Verify that there is no segfault when one thread is updating the > > + memory block of memcmp and the other thread is doing memcmp. */ > > + > > +#define TEST_MAIN > > +#define TEST_NAME "memcmp" > > + > > +#include <stdio.h> > > +#include <stdint.h> > > +#include <string.h> > > +#include <string/test-string.h> > > +#include <support/xthread.h> > > + > > +#define NUM_THREADS 2 > > +#define LOOP1 10000 > > +#define LOOP2 1000000 > > + > > +typedef int (*proto_t) (const void *, const void *, size_t); > > + > > +IMPL (memcmp, 1) > > + > > +struct arg > > +{ > > + proto_t func; > > + size_t len; > > + int i; > > +}; > > + > > +static void * > > +childThread (void *tArgs) > > +{ > > + struct arg *a = (struct arg *) tArgs; > > + int i; > > + > > + if (0 == a->i % 2) > > + { > > + for (i = 0; i < LOOP1; i++) > > + { > > + int result = a->func (buf1, buf2, a->len); > > So the test can catch more subtle errors can we test > with memcmp args at begining and end of a page. > > i.e buf1/buf2 and (buf1 + page_size - a->len)/(buf2 + page_size - a->len). I'd like to keep it as simple as possible to cover this particular race condition. Make it more complex may not provide additional coverage for race conditions. > > > + printf ("i = %d : result = %d\n", i, result); > > + } > > + } > > + else > > + { > > + size_t offset = a->len > 16 ? a->len - 16 : 1; > > + for (i = 0; i < LOOP2; i++) > > + buf1[offset] = i & 1; > > + } > > + > > + return NULL; > > +} > > + > > +static void > > +do_one_test (proto_t func, size_t len) > > +{ > > + int i; > > + pthread_t threads[NUM_THREADS]; > > + struct arg a[NUM_THREADS]; > > + > > + for (i = 0; i < NUM_THREADS; ++i) > > + { > > + a[i].func = func; > > + a[i].len = len; > > + a[i].i = i; > > + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); > > + } > > + > > + for (i = 0; i < NUM_THREADS; ++i) > > + xpthread_join (threads[i]); > > +} > > + > > +int > > +test_main (void) > > +{ > > + test_init (); > > + > > + memset (buf1, 1, page_size); > > + memset (buf2, 1, page_size); > > + > > + for (size_t i = 0; i <= 11; i++) > > + { > > + FOR_EACH_IMPL (impl, 0) > > + do_one_test ((proto_t) impl->fn, (1 << i) + 1); > can you also test 2^i - 1. Will add it. > > + } > > + > > + return 0; > > +} > > + > > +#include <support/test-driver.c> > > -- > > 2.38.1 > > > > Can you move this to the string directory (so we run this on all > arch) and add corresponding tests for memcmpeq/wmemcmp. I can move it to nptl since it is a threaded test. I will take a look at memcmpeq and wmemcmp.
On Mon, Dec 19, 2022 at 8:56 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > On Mon, Dec 19, 2022 at 6:39 AM Noah Goldstein <goldstein.w.n@gmail.com> wrote: > > > > On Wed, Dec 14, 2022 at 1:30 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > > > When a thread is updating the memory area of memcmp and another thread > > > is doing memcmp, the memcmp return value is undefined. Add a testcase > > > to verify that memcmp won't segfault in this case. > > > --- > > > sysdeps/x86/Makefile | 8 +++ > > > sysdeps/x86/tst-memcmp-race.c | 106 ++++++++++++++++++++++++++++++++++ > > > 2 files changed, 114 insertions(+) > > > create mode 100644 sysdeps/x86/tst-memcmp-race.c > > > > > > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile > > > index 56fd5fc805..c3f05a06ab 100644 > > > --- a/sysdeps/x86/Makefile > > > +++ b/sysdeps/x86/Makefile > > > @@ -257,3 +257,11 @@ tests += \ > > > tests-static += \ > > > tst-sysconf-cache-linesize-static > > > endif > > > + > > > +ifeq ($(subdir),nptl) > > > +tests += \ > > > + tst-memcmp-race \ > > > +# tests > > > + > > > +CFLAGS-tst-memcmp-race.c += -O0 > > > +endif > > > diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c > > > new file mode 100644 > > > index 0000000000..eefa9e43c4 > > > --- /dev/null > > > +++ b/sysdeps/x86/tst-memcmp-race.c > > > @@ -0,0 +1,106 @@ > > > +/* Test case for memcmp with race condition. > > > + Copyright (C) 2022 Free Software Foundation, Inc. > > > + This file is part of the GNU C Library. > > > + > > > + The GNU C Library is free software; you can redistribute it and/or > > > + modify it under the terms of the GNU Lesser General Public > > > + License as published by the Free Software Foundation; either > > > + version 2.1 of the License, or (at your option) any later version. > > > + > > > + The GNU C Library is distributed in the hope that it will be useful, > > > + but WITHOUT ANY WARRANTY; without even the implied warranty of > > > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > > + Lesser General Public License for more details. > > > + > > > + You should have received a copy of the GNU Lesser General Public > > > + License along with the GNU C Library; if not, see > > > + <https://www.gnu.org/licenses/>. */ > > > + > > > +/* Verify that there is no segfault when one thread is updating the > > > + memory block of memcmp and the other thread is doing memcmp. */ > > > + > > > +#define TEST_MAIN > > > +#define TEST_NAME "memcmp" > > > + > > > +#include <stdio.h> > > > +#include <stdint.h> > > > +#include <string.h> > > > +#include <string/test-string.h> > > > +#include <support/xthread.h> > > > + > > > +#define NUM_THREADS 2 > > > +#define LOOP1 10000 > > > +#define LOOP2 1000000 > > > + > > > +typedef int (*proto_t) (const void *, const void *, size_t); > > > + > > > +IMPL (memcmp, 1) > > > + > > > +struct arg > > > +{ > > > + proto_t func; > > > + size_t len; > > > + int i; > > > +}; > > > + > > > +static void * > > > +childThread (void *tArgs) > > > +{ > > > + struct arg *a = (struct arg *) tArgs; > > > + int i; > > > + > > > + if (0 == a->i % 2) > > > + { > > > + for (i = 0; i < LOOP1; i++) > > > + { > > > + int result = a->func (buf1, buf2, a->len); > > > > So the test can catch more subtle errors can we test > > with memcmp args at begining and end of a page. > > > > i.e buf1/buf2 and (buf1 + page_size - a->len)/(buf2 + page_size - a->len). > > I'd like to keep it as simple as possible to cover this > particular race condition. Make it more complex may > not provide additional coverage for race conditions. > Think the idea is since we want to make this test generic, it should provide actual coverage, not just test for the exact bug we had in memcmp-sse2. For example one of the toy impls brough up: for (i = 0; i + 4; i < n; i += 4) { u32 a32 = *(u32 *)(a + i); u32 b32 = *(u32 *)(b + i); if(a32 != b32) { for(; a[i] - b[i] == 0; ++i); return a[i] - b[i]; } } might overread just a few bytes and we probably want to at least be aware of that. > > > > > + printf ("i = %d : result = %d\n", i, result); > > > + } > > > + } > > > + else > > > + { > > > + size_t offset = a->len > 16 ? a->len - 16 : 1; > > > + for (i = 0; i < LOOP2; i++) > > > + buf1[offset] = i & 1; > > > + } > > > + > > > + return NULL; > > > +} > > > + > > > +static void > > > +do_one_test (proto_t func, size_t len) > > > +{ > > > + int i; > > > + pthread_t threads[NUM_THREADS]; > > > + struct arg a[NUM_THREADS]; > > > + > > > + for (i = 0; i < NUM_THREADS; ++i) > > > + { > > > + a[i].func = func; > > > + a[i].len = len; > > > + a[i].i = i; > > > + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); > > > + } > > > + > > > + for (i = 0; i < NUM_THREADS; ++i) > > > + xpthread_join (threads[i]); > > > +} > > > + > > > +int > > > +test_main (void) > > > +{ > > > + test_init (); > > > + > > > + memset (buf1, 1, page_size); > > > + memset (buf2, 1, page_size); > > > + > > > + for (size_t i = 0; i <= 11; i++) > > > + { > > > + FOR_EACH_IMPL (impl, 0) > > > + do_one_test ((proto_t) impl->fn, (1 << i) + 1); > > can you also test 2^i - 1. > > Will add it. > > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +#include <support/test-driver.c> > > > -- > > > 2.38.1 > > > > > > > Can you move this to the string directory (so we run this on all > > arch) and add corresponding tests for memcmpeq/wmemcmp. > > I can move it to nptl since it is a threaded test. I will take a look > at memcmpeq and wmemcmp. > > -- > H.J.
On Mon, Dec 19, 2022 at 9:50 AM Noah Goldstein <goldstein.w.n@gmail.com> wrote: > > On Mon, Dec 19, 2022 at 8:56 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > On Mon, Dec 19, 2022 at 6:39 AM Noah Goldstein <goldstein.w.n@gmail.com> wrote: > > > > > > On Wed, Dec 14, 2022 at 1:30 PM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > > > > > When a thread is updating the memory area of memcmp and another thread > > > > is doing memcmp, the memcmp return value is undefined. Add a testcase > > > > to verify that memcmp won't segfault in this case. > > > > --- > > > > sysdeps/x86/Makefile | 8 +++ > > > > sysdeps/x86/tst-memcmp-race.c | 106 ++++++++++++++++++++++++++++++++++ > > > > 2 files changed, 114 insertions(+) > > > > create mode 100644 sysdeps/x86/tst-memcmp-race.c > > > > > > > > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile > > > > index 56fd5fc805..c3f05a06ab 100644 > > > > --- a/sysdeps/x86/Makefile > > > > +++ b/sysdeps/x86/Makefile > > > > @@ -257,3 +257,11 @@ tests += \ > > > > tests-static += \ > > > > tst-sysconf-cache-linesize-static > > > > endif > > > > + > > > > +ifeq ($(subdir),nptl) > > > > +tests += \ > > > > + tst-memcmp-race \ > > > > +# tests > > > > + > > > > +CFLAGS-tst-memcmp-race.c += -O0 > > > > +endif > > > > diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c > > > > new file mode 100644 > > > > index 0000000000..eefa9e43c4 > > > > --- /dev/null > > > > +++ b/sysdeps/x86/tst-memcmp-race.c > > > > @@ -0,0 +1,106 @@ > > > > +/* Test case for memcmp with race condition. > > > > + Copyright (C) 2022 Free Software Foundation, Inc. > > > > + This file is part of the GNU C Library. > > > > + > > > > + The GNU C Library is free software; you can redistribute it and/or > > > > + modify it under the terms of the GNU Lesser General Public > > > > + License as published by the Free Software Foundation; either > > > > + version 2.1 of the License, or (at your option) any later version. > > > > + > > > > + The GNU C Library is distributed in the hope that it will be useful, > > > > + but WITHOUT ANY WARRANTY; without even the implied warranty of > > > > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > > > + Lesser General Public License for more details. > > > > + > > > > + You should have received a copy of the GNU Lesser General Public > > > > + License along with the GNU C Library; if not, see > > > > + <https://www.gnu.org/licenses/>. */ > > > > + > > > > +/* Verify that there is no segfault when one thread is updating the > > > > + memory block of memcmp and the other thread is doing memcmp. */ > > > > + > > > > +#define TEST_MAIN > > > > +#define TEST_NAME "memcmp" > > > > + > > > > +#include <stdio.h> > > > > +#include <stdint.h> > > > > +#include <string.h> > > > > +#include <string/test-string.h> > > > > +#include <support/xthread.h> > > > > + > > > > +#define NUM_THREADS 2 > > > > +#define LOOP1 10000 > > > > +#define LOOP2 1000000 > > > > + > > > > +typedef int (*proto_t) (const void *, const void *, size_t); > > > > + > > > > +IMPL (memcmp, 1) > > > > + > > > > +struct arg > > > > +{ > > > > + proto_t func; > > > > + size_t len; > > > > + int i; > > > > +}; > > > > + > > > > +static void * > > > > +childThread (void *tArgs) > > > > +{ > > > > + struct arg *a = (struct arg *) tArgs; > > > > + int i; > > > > + > > > > + if (0 == a->i % 2) > > > > + { > > > > + for (i = 0; i < LOOP1; i++) > > > > + { > > > > + int result = a->func (buf1, buf2, a->len); > > > > > > So the test can catch more subtle errors can we test > > > with memcmp args at begining and end of a page. > > > > > > i.e buf1/buf2 and (buf1 + page_size - a->len)/(buf2 + page_size - a->len). > > > > I'd like to keep it as simple as possible to cover this > > particular race condition. Make it more complex may > > not provide additional coverage for race conditions. > > > > Think the idea is since we want to make this test generic, > it should provide actual coverage, not just test for the exact > bug we had in memcmp-sse2. > > For example one of the toy impls brough up: > > for (i = 0; i + 4; i < n; i += 4) { > u32 a32 = *(u32 *)(a + i); > u32 b32 = *(u32 *)(b + i); > if(a32 != b32) { > for(; a[i] - b[i] == 0; ++i); > return a[i] - b[i]; > } > } > > might overread just a few bytes and we probably > want to at least be aware of that. We need to verify that it triggers the segfault without the fix. > > > > > > > > + printf ("i = %d : result = %d\n", i, result); > > > > + } > > > > + } > > > > + else > > > > + { > > > > + size_t offset = a->len > 16 ? a->len - 16 : 1; > > > > + for (i = 0; i < LOOP2; i++) > > > > + buf1[offset] = i & 1; > > > > + } > > > > + > > > > + return NULL; > > > > +} > > > > + > > > > +static void > > > > +do_one_test (proto_t func, size_t len) > > > > +{ > > > > + int i; > > > > + pthread_t threads[NUM_THREADS]; > > > > + struct arg a[NUM_THREADS]; > > > > + > > > > + for (i = 0; i < NUM_THREADS; ++i) > > > > + { > > > > + a[i].func = func; > > > > + a[i].len = len; > > > > + a[i].i = i; > > > > + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); > > > > + } > > > > + > > > > + for (i = 0; i < NUM_THREADS; ++i) > > > > + xpthread_join (threads[i]); > > > > +} > > > > + > > > > +int > > > > +test_main (void) > > > > +{ > > > > + test_init (); > > > > + > > > > + memset (buf1, 1, page_size); > > > > + memset (buf2, 1, page_size); > > > > + > > > > + for (size_t i = 0; i <= 11; i++) > > > > + { > > > > + FOR_EACH_IMPL (impl, 0) > > > > + do_one_test ((proto_t) impl->fn, (1 << i) + 1); > > > can you also test 2^i - 1. > > > > Will add it. > > > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +#include <support/test-driver.c> > > > > -- > > > > 2.38.1 > > > > > > > > > > Can you move this to the string directory (so we run this on all > > > arch) and add corresponding tests for memcmpeq/wmemcmp. > > > > I can move it to nptl since it is a threaded test. I will take a look > > at memcmpeq and wmemcmp. > > > > -- > > H.J.
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile index 56fd5fc805..c3f05a06ab 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile @@ -257,3 +257,11 @@ tests += \ tests-static += \ tst-sysconf-cache-linesize-static endif + +ifeq ($(subdir),nptl) +tests += \ + tst-memcmp-race \ +# tests + +CFLAGS-tst-memcmp-race.c += -O0 +endif diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c new file mode 100644 index 0000000000..eefa9e43c4 --- /dev/null +++ b/sysdeps/x86/tst-memcmp-race.c @@ -0,0 +1,106 @@ +/* Test case for memcmp with race condition. + Copyright (C) 2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +/* Verify that there is no segfault when one thread is updating the + memory block of memcmp and the other thread is doing memcmp. */ + +#define TEST_MAIN +#define TEST_NAME "memcmp" + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <string/test-string.h> +#include <support/xthread.h> + +#define NUM_THREADS 2 +#define LOOP1 10000 +#define LOOP2 1000000 + +typedef int (*proto_t) (const void *, const void *, size_t); + +IMPL (memcmp, 1) + +struct arg +{ + proto_t func; + size_t len; + int i; +}; + +static void * +childThread (void *tArgs) +{ + struct arg *a = (struct arg *) tArgs; + int i; + + if (0 == a->i % 2) + { + for (i = 0; i < LOOP1; i++) + { + int result = a->func (buf1, buf2, a->len); + printf ("i = %d : result = %d\n", i, result); + } + } + else + { + size_t offset = a->len > 16 ? a->len - 16 : 1; + for (i = 0; i < LOOP2; i++) + buf1[offset] = i & 1; + } + + return NULL; +} + +static void +do_one_test (proto_t func, size_t len) +{ + int i; + pthread_t threads[NUM_THREADS]; + struct arg a[NUM_THREADS]; + + for (i = 0; i < NUM_THREADS; ++i) + { + a[i].func = func; + a[i].len = len; + a[i].i = i; + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); + } + + for (i = 0; i < NUM_THREADS; ++i) + xpthread_join (threads[i]); +} + +int +test_main (void) +{ + test_init (); + + memset (buf1, 1, page_size); + memset (buf2, 1, page_size); + + for (size_t i = 0; i <= 11; i++) + { + FOR_EACH_IMPL (impl, 0) + do_one_test ((proto_t) impl->fn, (1 << i) + 1); + } + + return 0; +} + +#include <support/test-driver.c>