lib: add safe_pthread_create() & safe_pthread_join()
PATCH v2 1/2 lib: add safe_pthread_create() & safe_pthread_join()
--- include/tst_safe_pthread.h | 32 ++++++++++++++++++++++++++ include/tst_test.h | 1 + lib/safe_pthread.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 0 deletions(-) create mode 100644 include/tst_safe_pthread.h create mode 100644 lib/safe_pthread.c
include/tst_safe_pthread.h new file +32 -0
@@ -0,0 +1,32 @@ +/* +* Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef TST_SAFE_PTHREAD_H__ +#define TST_SAFE_PTHREAD_H__ + +int safe_pthread_create (const char *file,const int lineno, +pthread_t *thread_id,const pthread_attr_t *attr, +void *(*thread_fn)(void *),void *arg); +#define SAFE_PTHREAD_CREATE (thread_id, attr, thread_fn, arg) \ + safe_pthread_create(__FILE__, __LINE__, thread_id, attr, thread_fn, arg) + +int safe_pthread_join (const char *file,const int lineno, +pthread_t thread_id,void **retval); +#define SAFE_PTHREAD_JOIN (thread_id, retval) \ + safe_pthread_join(__FILE__, __LINE__, thread_id, retval) + +#endif /* TST_SAFE_PTHREAD_H__ */
include/tst_test.h +1 -0
@@ -60,6 +60,7 @@ pid_t safe_fork(const char *filename, unsigned int lineno);#include "tst_safe_macros.h" #include "tst_safe_file_ops.h" #include "tst_safe_net.h" +#include "tst_safe_pthread.h" struct tst_option {char *optstr;
lib/safe_pthread.c new file +54 -0
54 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH v2 2/2 syscalls/fcntl: add new test for open file description locks
OFD lock is available since Linux 3.15 and new F_OFD_* macros added to lapi/fcntl.h
Test is based on [1] article and checks that OFD locks can syncronise access to a file between multiple threads.
[1] https://lwn.net/Articles/586904
---
v2: * correct varibale names
* use new library API
* truncate test file before threads start
* use safe_pthread_*()
include/lapi/fcntl.h | 12 +++ runtest/syscalls | 2 + testcases/kernel/syscalls/.gitignore | 2 + testcases/kernel/syscalls/fcntl/Makefile | 3 + testcases/kernel/syscalls/fcntl/fcntl34.c | 149 +++++++++++++++++++++++++++++ 5 files changed, 168 insertions(+), 0 deletions(-) create mode 100644 testcases/kernel/syscalls/fcntl/fcntl34.c
include/lapi/fcntl.h +12 -0
@@ -43,6 +43,18 @@# define F_OWNER_PGRP 2#endif +#ifndef F_OFD_GETLK +# define F_OFD_GETLK 36 +#endif + +#ifndef F_OFD_SETLK +# define F_OFD_SETLK 37 +#endif + +#ifndef F_OFD_SETLKW +# define F_OFD_SETLKW 38 +#endif +#ifndef AT_FDCWD # define AT_FDCWD -100#endif
runtest/syscalls +2 -0
@@ -265,6 +265,8 @@ fcntl32 fcntl32 fcntl32_64 fcntl32_64 fcntl33 fcntl33 fcntl33_64 fcntl33_64 +fcntl34 fcntl34 +fcntl34_64 fcntl34_64 fdatasync01 fdatasync01 fdatasync02 fdatasync02
testcases/kernel/syscalls/.gitignore +2 -0
@@ -228,6 +228,8 @@ /fcntl/fcntl32_64 /fcntl/fcntl33 /fcntl/fcntl33_64 +/fcntl/fcntl34 +/fcntl/fcntl34_64 /fdatasync/fdatasync01 /fdatasync/fdatasync02 /flock/flock01
testcases/kernel/syscalls/fcntl/Makefile +3 -0
@@ -21,6 +21,9 @@ top_srcdir ?= ../../../.. fcntl33: LDLIBS+=-lrt fcntl33_64: LDLIBS+=-lrt +fcntl34: LDLIBS += -lpthread +fcntl34_64: LDLIBS += -lpthread + include $(top_srcdir)/include/mk/testcases.mk include $(abs_srcdir)/../utils/newer_64.mk
testcases/kernel/syscalls/fcntl/fcntl34.c new file +149 -0
149 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH v2 2/2 syscalls/fcntl: add new test for open file description locks
Hi!
Quoted 75 lines
testcases/kernel/syscalls/fcntl/fcntl34.c new file +75
-0+#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> + +#include "lapi/fcntl.h" +#include "tst_test.h" + +static int thread_cnt; +static const int max_thread_cnt =32 ; +static const char fname[] ="tst_ofd_locks" ; +const int writes_num =100 ; +const int write_size =4096 ; + +static void setup (void ) +{ + thread_cnt =tst_ncpus_conf () *3 ; +if (thread_cnt > max_thread_cnt) + thread_cnt = max_thread_cnt; +} + +static void spawn_threads (pthread_t *id,void *(*thread_fn)(void *)) +{ +intptr_t i; + +tst_res (TINFO ,"spawning '%d' threads" , thread_cnt); +for (i =0 ; i < thread_cnt; ++i) +SAFE_PTHREAD_CREATE (id + i,NULL , thread_fn, (void *)i); +} + +static void wait_threads (pthread_t *id) +{ +int i; + +tst_res (TINFO ,"waiting for '%d' threads" , thread_cnt); +for (i =0 ; i < thread_cnt; ++i) +SAFE_PTHREAD_JOIN (id[i],NULL ); +} + +void *thread_fn_01 (void *arg) +{ +int i; +char buf[write_size]; +int fd =SAFE_OPEN (fname,O_RDWR ); + +memset (buf, (intptr_t )arg, write_size); + +struct flock lck = { + .l_whence =SEEK_SET , + .l_start =0 , + .l_len =1 , + }; + +for (i =0 ; i < writes_num; ++i) { + lck.l_type =F_WRLCK ; +if (fcntl (fd,F_OFD_SETLKW , &lck) ==-1 ) +tst_brk (TBROK |TERRNO ,"fcntl() failed" ); + +SAFE_LSEEK (fd,0 ,SEEK_END ); +SAFE_WRITE (1 , fd, buf, write_size); + + lck.l_type =F_UNLCK ; +if (fcntl (fd,F_OFD_SETLKW , &lck) ==-1 ) +tst_brk (TBROK |TERRNO ,"fcntl() failed" ); + +pthread_yield (); + } + +SAFE_CLOSE (fd); + +return NULL ; +} + +static void test01 (void )
testcases/kernel/syscalls/fcntl/fcntl34.c line 105
Quoted 10 lines
testcases/kernel/syscalls/fcntl/fcntl34.c new file +10
-0+{ +intptr_t i; +int k; +pthread_t id[thread_cnt]; +int res[thread_cnt]; +char buf[write_size]; + +tst_res (TINFO ,"write to a file inside threads with OFD locks" ); + +int fd =SAFE_OPEN (fname,O_CREAT |O_TRUNC |O_RDONLY ,0600 );
I'm not sure that O_TRUNC | O_RDONLY would work. The manual says that the result is unspecified.
We should either change the O_RDONLY for O_RDWR or simply unlink() the file before we open it.
Otherwise (with the unsigned char buffer) it looks fine.
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 2/2 syscalls/fcntl: add new test for open file description locks
In reply to Alexey KodanevHi,
Quoted 7 lines · Alexey Kodanev
OFD lock is available since Linux 3.15 and new F_OFD_* macros added to
lapi/fcntl.hTest is based on [1] article and checks that OFD locks can syncronise access to a file between multiple threads.
Patch-set applied.
Best regards,
Alexey
PATCH v2 1/2 lib: add safe_pthread_create() & safe_pthread_join()
In reply to Alexey KodanevHi!
lib/safe_pthread.c line 50
Quoted 11 lines
lib/safe_pthread.c new file +11
-0+int safe_pthread_join (const char *file,const int lineno, +pthread_t thread_id,void **retval) +{ +int rval; + + rval =pthread_join (thread_id, retval); + +if (rval) { +tst_brk_ (file, lineno,TBROK , +"pthread_join(%lu,%p) failed: %s" , thread_id, retval, +tst_strerrno (rval));
Technically the thread_id does not need to be numeric type, POSIX defines it as a opaque, may be structure as well.
But on the other hand I doubt that there is a Linux libc implementation that actually defines it to be anything else than long int.
lib/safe_pthread.c line 38
Quoted 4 lines
lib/safe_pthread.c new file +4
-0+ } + +return rval; +}
Otherwise this looks fine.
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 1/2 lib: add safe_pthread_create() & safe_pthread_join()
Hi,
Quoted 14 lines · Cyril Hrubis
Hi!
lib/safe_pthread.c line 50
Quoted 11 lines
lib/safe_pthread.c new file +11
-0+int safe_pthread_join (const char *file,const int lineno, +pthread_t thread_id,void **retval) +{ +int rval; + + rval =pthread_join (thread_id, retval); + +if (rval) { +tst_brk_ (file, lineno,TBROK , +"pthread_join(%lu,%p) failed: %s" , thread_id, retval, +tst_strerrno (rval));Technically the
thread_iddoes not need to be numeric type, POSIX defines it as a opaque, may be structure as well.
We could print in hex like this:
if (rval) {
unsigned int i;
unsigned char *ptr = (unsigned char *)&thread_id;
size_t tid_size = sizeof(thread_id);
char buf[tid_size * 2 + 1];
for (i = 0; i < tid_size; ++i)
sprintf(buf + i * 2, "%02x", ptr[i]);
tst_brk_(file, lineno, TBROK,
"pthread_join(%s,%p) failed: %s", buf, retval, ...);
}But bytes might be in different order due to endianness, supposing we compare this value with "%lx", e.g. on x86_64
00971fe3257f0000 vs 7f25e31f9700 (%lx)
What do you think?
Thanks,
Alexey
Quoted 9 lines
But on the other hand I doubt that there is a Linux libc implementation that actually defines it to be anything else than long int.
lib/safe_pthread.c line 38
Quoted 4 lines
lib/safe_pthread.c new file +4
-0+ } + +return rval; +}Otherwise this looks fine.
PATCH v2 1/2 lib: add safe_pthread_create() & safe_pthread_join()
Hi!
Quoted 18 lines
Quoted 2 lines
Technically the
thread_iddoes not need to be numeric type, POSIX defines it as a opaque, may be structure as well.We could print in hex like this:
if (rval) { unsigned int i; unsigned char *ptr = (unsigned char *)&thread_id; size_t tid_size = sizeof(thread_id); char buf[tid_size * 2 + 1]; for (i = 0; i < tid_size; ++i) sprintf(buf + i * 2, "%02x", ptr[i]); tst_brk_(file, lineno, TBROK, "pthread_join(%s,%p) failed: %s", buf, retval, ...); }
Quoted 6 lines
But bytes might be in different order due to endianness, supposing we compare this value with "%lx", e.g. on
x86_64
00971fe3257f0000vs7f25e31f9700(%lx)What do you think?
I'm starting to consider not printing the value at all, since it's not that important as gdb and strace pthread ids are not related to the value of pthread_t. We can just print "pthread_join(..., %p)" instead.
Or we can add a configure check if pthread_t is actually numeric. Something as:
pthread_t *t = (unsigned long*)NULL;
Should fail with -Werror unless pthread_t is defined as unsigned long.
Then we can proceed with printing it with "%ul" if the check was OK, but I'm not sure that it's worth of the work.
Signature · 2 lines
Cyril Hrubis [email protected]
PATCH v2 1/2 lib: add safe_pthread_create() & safe_pthread_join()
Hi,
Quoted 21 lines · Cyril Hrubis
Hi!
Quoted 20 lines
Quoted 2 lines
Technically the
thread_iddoes not need to be numeric type, POSIX defines it as a opaque, may be structure as well.We could print in hex like this:
if (rval) { unsigned int i; unsigned char *ptr = (unsigned char *)&thread_id; size_t tid_size = sizeof(thread_id); char buf[tid_size * 2 + 1]; for (i = 0; i < tid_size; ++i) sprintf(buf + i * 2, "%02x", ptr[i]); tst_brk_(file, lineno, TBROK, "pthread_join(%s,%p) failed: %s", buf, retval, ...); }But bytes might be in different order due to endianness, supposing we compare this value with "%lx", e.g. on
x86_64
Quoted 6 lines
Quoted 3 lines
00971fe3257f0000vs7f25e31f9700(%lx)What do you think?
I'm starting to consider not printing the value at all, since it's not that important as gdb and strace pthread ids are not related to the value of
pthread_t. We can just print "pthread_join(..., %p)" instead.
Agree.
Quoted 9 lines
Or we can add a configure check if
pthread_tis actually numeric. Something as:pthread_t *t = (unsigned long*)NULL;Should fail with -Werror unless
pthread_tis defined as unsigned long.Then we can proceed with printing it with "%ul" if the check was OK, but I'm not sure that it's worth of the work.
OK. For now, we can add it into TODO list.
Thanks,
Alexey