Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On 12/12/2017 02:41 PM, Eric Blake wrote: > On 12/11/2017 03:32 PM, Paolo Bonzini wrote: >> On 11/12/2017 15:11, Eric Blake wrote: >>> I don't know if there is a way to make gcc insert stack-unwind >>> directives that are honored across longjmp (I know C++ does it for >>> exceptions; so there may be a way, and I just don't know it). >> >> Probably -fexceptions. >> > > Well, that's what 'info gcc' mentions: > > 'cleanup (CLEANUP_FUNCTION)' > The 'cleanup' attribute runs a function when the variable goes out > of scope. This attribute can only be applied to auto function > scope variables; it may not be applied to parameters or variables > with static storage duration. The function must take one > parameter, a pointer to a type compatible with the variable. The > return value of the function (if any) is ignored. > > If '-fexceptions' is enabled, then CLEANUP_FUNCTION is run during > the stack unwinding that happens during the processing of the > exception. Note that the 'cleanup' attribute does not allow the > exception to be caught, only to perform an action. It is undefined > what happens if CLEANUP_FUNCTION does not return normally. > > but adding -fexceptions to my sample program does NOT make a difference > (apparently, unwind cleanup triggered by C++ exceptions is NOT the same > as unwinding done by longjmp()). longjmp isn't an exception, and so doesn't run stack cleanups. You'd need to use _Unwind_Throw ... except for the fact that C doesn't have a mechanism by which we can catch it. We would really need to use C++ and throw to get those semantics. r~
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On 12/11/2017 03:32 PM, Paolo Bonzini wrote: > On 11/12/2017 15:11, Eric Blake wrote: >> I don't know if there is a way to make gcc insert stack-unwind >> directives that are honored across longjmp (I know C++ does it for >> exceptions; so there may be a way, and I just don't know it). > > Probably -fexceptions. > Well, that's what 'info gcc' mentions: 'cleanup (CLEANUP_FUNCTION)' The 'cleanup' attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored. If '-fexceptions' is enabled, then CLEANUP_FUNCTION is run during the stack unwinding that happens during the processing of the exception. Note that the 'cleanup' attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if CLEANUP_FUNCTION does not return normally. but adding -fexceptions to my sample program does NOT make a difference (apparently, unwind cleanup triggered by C++ exceptions is NOT the same as unwinding done by longjmp()). -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On Fri, Dec 08, 2017 at 11:55:48 +0100, Paolo Bonzini wrote: > So I'm a bit underwhelmed by this experiment. Other opinions? I am on the same boat. Most use cases in this patchset are arguably adding more complexity because they substitute already very simple code (e.g. "lock; do_something; unlock"), as others have pointed out as well. I usually deal with tricky cases (i.e. functions with many return paths) with an inline "__locked" function. In most cases this will be clearer than using the macros. I concede though that the separate inline is not always an option. That said, two comments: - We might be better off just exposing the cleanup attribute via some convenience macros. The systemd codebase does this, mostly for freeing memory or closing file descriptors. I suspect a large percentage of goto's in our codebase could be eliminated. This could be also used for locks, although we'd need a variant of mutex_lock that returned the mutex, so that in the cleanup function we could just check for NULL. - Does the cleanup attribute work on all compilers used to build QEMU? (I'm thinking of Windows in particular.) Thanks, Emilio
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On 11/12/2017 15:11, Eric Blake wrote: > I don't know if there is a way to make gcc insert stack-unwind > directives that are honored across longjmp (I know C++ does it for > exceptions; so there may be a way, and I just don't know it). Probably -fexceptions. Paolo > Conversely, I do know that pthread_cleanup_push/pop, which does > something similar, is permitted by POSIX to NOT work across longjmp: > >Calling longjmp(3) (siglongjmp(3)) produces undefined results > if any >call has been made to pthread_cleanup_push() or > pthread_cleanup_pop() >without the matching call of the pair since the jump buffer was > filled >by setjmp(3) (sigsetjmp(3)). Likewise, calling longjmp(3) > (sig‐ >longjmp(3)) from inside a clean-up handler produces undefined > results >unless the jump buffer was also filled by setjmp(3) > (sigsetjmp(3)) >inside the handler. signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On 12/11/2017 03:38 AM, Peter Maydell wrote: > On 8 December 2017 at 19:40, Eric Blake wrote: >> On 12/08/2017 04:55 AM, Paolo Bonzini wrote: >>> Likewise, >>> >>> QEMU_WITH_LOCK(QemuMutex, guard_name, &some_mutex) { >>> ... >>> } >>> >>> is the same as >>> >>> qemu_mutex_lock(&some_mutex); >>> ... >>> qemu_mutex_unlock(&some_mutex); >>> >>> except that any returns within the region will unlock the mutex. >> >> Not just returns, but ANY manner that you leave the scope, including a >> goto or just falling out of the end of the scope. > > How about longjmp()ing out of it? Easy to test: == #include #include #include void my_cleanup (int *ptr) { int *i = ptr; printf("in my_cleanup(%d)\n", *i); } jmp_buf jmp; void foo(int i) { while (1) { __attribute__((cleanup(my_cleanup))) int j = i; if (i == 0) { printf("before leaving scope by return\n"); return; } if (i == 1) { goto label; } if (i == 3) { longjmp(jmp, 1); } if (i == 4) { printf("before leaving scope by exit\n"); exit(0); } break; } printf("after leaving scope by break\n"); return; label: printf("after leaving scope by return\n"); } int main(void) { foo(0); foo(1); foo(2); if (!setjmp(jmp)) { foo(3); } printf("after leaving scope by longjmp\n"); foo(4); } But the results aren't necessarily nice, depending on how we currently (ab)use longjmp. Under Fedora 27 gcc (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2) I get $ ./foo before leaving scope by return in my_cleanup(0) in my_cleanup(1) after leaving scope by return in my_cleanup(2) after leaving scope by break after leaving scope by longjmp before leaving scope by exit I don't know if there is a way to make gcc insert stack-unwind directives that are honored across longjmp (I know C++ does it for exceptions; so there may be a way, and I just don't know it). Conversely, I do know that pthread_cleanup_push/pop, which does something similar, is permitted by POSIX to NOT work across longjmp: Calling longjmp(3) (siglongjmp(3)) produces undefined results if any call has been made to pthread_cleanup_push() or pthread_cleanup_pop() without the matching call of the pair since the jump buffer was filled by setjmp(3) (sigsetjmp(3)). Likewise, calling longjmp(3) (sig‐ longjmp(3)) from inside a clean-up handler produces undefined results unless the jump buffer was also filled by setjmp(3) (sigsetjmp(3)) inside the handler. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On 8 December 2017 at 19:40, Eric Blake wrote: > On 12/08/2017 04:55 AM, Paolo Bonzini wrote: >> Likewise, >> >> QEMU_WITH_LOCK(QemuMutex, guard_name, &some_mutex) { >> ... >> } >> >> is the same as >> >> qemu_mutex_lock(&some_mutex); >> ... >> qemu_mutex_unlock(&some_mutex); >> >> except that any returns within the region will unlock the mutex. > > Not just returns, but ANY manner that you leave the scope, including a > goto or just falling out of the end of the scope. How about longjmp()ing out of it? thanks -- PMM
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
Hi, This series seems to have some coding style problems. See output below for more information: Message-id: 20171208105553.12249-1-pbonz...@redhat.com Subject: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)) Type: series === TEST SCRIPT BEGIN === #!/bin/bash BASE=base n=1 total=$(git log --oneline $BASE.. | wc -l) failed=0 git config --local diff.renamelimit 0 git config --local diff.renames True commits="$(git log --format=%H --reverse $BASE..)" for c in $commits; do echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..." if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then failed=1 echo fi n=$((n+1)) done exit $failed === TEST SCRIPT END === Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 Switched to a new branch 'test' 8e9ffc046d thread-pool: convert to use lock guards 007b5bc7b3 qht: convert to use lock guards 6fd333cacc qemu-timer: convert to use lock guards 1a895608bb lock-guard: add scoped lock implementation 2188a83be2 compiler: add a helper for C99 inline functions === OUTPUT BEGIN === Checking PATCH 1/5: compiler: add a helper for C99 inline functions... Checking PATCH 2/5: lock-guard: add scoped lock implementation... Checking PATCH 3/5: qemu-timer: convert to use lock guards... WARNING: line over 80 characters #54: FILE: util/qemu-timer.c:410: +QEMU_LOCK_GUARD(QemuMutex, timers_guard, &timer_list->active_timers_lock); ERROR: space required before the open parenthesis '(' #115: FILE: util/qemu-timer.c:519: +for(;;) { total: 1 errors, 1 warnings, 129 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. Checking PATCH 4/5: qht: convert to use lock guards... Checking PATCH 5/5: thread-pool: convert to use lock guards... === OUTPUT END === Test command exited with code: 1 --- Email generated automatically by Patchew [http://patchew.org/]. Please send your feedback to patchew-de...@freelists.org
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
Hi, This series failed automatic build test. Please find the testing commands and their output below. If you have docker installed, you can probably reproduce it locally. Message-id: 20171208105553.12249-1-pbonz...@redhat.com Subject: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)) Type: series === TEST SCRIPT BEGIN === #!/bin/bash set -e git submodule update --init dtc # Let docker tests dump environment info export SHOW_ENV=1 export J=8 time make docker-test-quick@centos6 time make docker-test-build@min-glib time make docker-test-mingw@fedora # iotests is broken now, skip # time make docker-test-block@fedora === TEST SCRIPT END === Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 From https://github.com/patchew-project/qemu * [new tag] patchew/20171208105553.12249-1-pbonz...@redhat.com -> patchew/20171208105553.12249-1-pbonz...@redhat.com Switched to a new branch 'test' 8e9ffc046d thread-pool: convert to use lock guards 007b5bc7b3 qht: convert to use lock guards 6fd333cacc qemu-timer: convert to use lock guards 1a895608bb lock-guard: add scoped lock implementation 2188a83be2 compiler: add a helper for C99 inline functions === OUTPUT BEGIN === Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc' Cloning into '/var/tmp/patchew-tester-tmp-k2f3p02l/src/dtc'... Submodule path 'dtc': checked out '558cd81bdd432769b59bff01240c44f82cfb1a9d' BUILD centos6 make[1]: Entering directory '/var/tmp/patchew-tester-tmp-k2f3p02l/src' GEN /var/tmp/patchew-tester-tmp-k2f3p02l/src/docker-src.2017-12-11-01.38.48.5601/qemu.tar Cloning into '/var/tmp/patchew-tester-tmp-k2f3p02l/src/docker-src.2017-12-11-01.38.48.5601/qemu.tar.vroot'... done. Checking out files: 46% (2622/5663) Checking out files: 47% (2662/5663) Checking out files: 48% (2719/5663) Checking out files: 49% (2775/5663) Checking out files: 50% (2832/5663) Checking out files: 51% (2889/5663) Checking out files: 52% (2945/5663) Checking out files: 53% (3002/5663) Checking out files: 54% (3059/5663) Checking out files: 55% (3115/5663) Checking out files: 56% (3172/5663) Checking out files: 57% (3228/5663) Checking out files: 58% (3285/5663) Checking out files: 59% (3342/5663) Checking out files: 60% (3398/5663) Checking out files: 61% (3455/5663) Checking out files: 62% (3512/5663) Checking out files: 63% (3568/5663) Checking out files: 64% (3625/5663) Checking out files: 65% (3681/5663) Checking out files: 66% (3738/5663) Checking out files: 67% (3795/5663) Checking out files: 68% (3851/5663) Checking out files: 69% (3908/5663) Checking out files: 70% (3965/5663) Checking out files: 71% (4021/5663) Checking out files: 72% (4078/5663) Checking out files: 73% (4134/5663) Checking out files: 74% (4191/5663) Checking out files: 75% (4248/5663) Checking out files: 76% (4304/5663) Checking out files: 77% (4361/5663) Checking out files: 78% (4418/5663) Checking out files: 79% (4474/5663) Checking out files: 80% (4531/5663) Checking out files: 81% (4588/5663) Checking out files: 82% (4644/5663) Checking out files: 83% (4701/5663) Checking out files: 84% (4757/5663) Checking out files: 85% (4814/5663) Checking out files: 86% (4871/5663) Checking out files: 87% (4927/5663) Checking out files: 88% (4984/5663) Checking out files: 89% (5041/5663) Checking out files: 90% (5097/5663) Checking out files: 91% (5154/5663) Checking out files: 92% (5210/5663) Checking out files: 93% (5267/5663) Checking out files: 94% (5324/5663) Checking out files: 95% (5380/5663) Checking out files: 96% (5437/5663) Checking out files: 97% (5494/5663) Checking out files: 98% (5550/5663) Checking out files: 99% (5607/5663) Checking out files: 100% (5663/5663) Checking out files: 100% (5663/5663), done. Your branch is up-to-date with 'origin/test'. Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc' Cloning into '/var/tmp/patchew-tester-tmp-k2f3p02l/src/docker-src.2017-12-11-01.38.48.5601/qemu.tar.vroot/dtc'... Submodule path 'dtc': checked out '558cd81bdd432769b59bff01240c44f82cfb1a9d' Submodule 'ui/keycodemapdb' (git://git.qemu.org/keycodemapdb.git) registered for path 'ui/keycodemapdb' Cloning into '/var/tmp/patchew-tester-tmp-k2f3p02l/src/docker-src.2017-12-11-01.38.48.5601/qemu.tar.vroot/ui/keycodemapdb'... Submodule path 'ui/keycodemapdb': checked out '10739aa26051a5d49d88132604539d3ed085e72e' COPYRUNNER RUN test-quick in qemu:centos6 Packages installed: SDL-devel-1.2.14-7.el6_7.1.x86_64 bison-2.4.1-5.el6.x86_64 bzip2-devel-1.0.5-7.el6_0.x86_64 ccache-3.1.6-2.el6.x86_64 cs
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
On 12/08/2017 04:55 AM, Paolo Bonzini wrote: > This is an attempt to make a C API that resembles the C++ > std::unique_lock (mostly untested). The idea is that you can write > > QEMU_LOCK_GUARD(QemuMutex, guard_name, &some_mutex); > > instead of > > qemu_mutex_lock(&some_mutex); > ... > out: > qemu_mutex_unlock(&some_mutex); > > and the mutex will be unlocked on all exit paths. In C++ that > would be "std::unique_lock guard_name(some_mutex);". > Likewise, > > QEMU_WITH_LOCK(QemuMutex, guard_name, &some_mutex) { > ... > } > > is the same as > > qemu_mutex_lock(&some_mutex); > ... > qemu_mutex_unlock(&some_mutex); > > except that any returns within the region will unlock the mutex. Not just returns, but ANY manner that you leave the scope, including a goto or just falling out of the end of the scope. (and, as Stefan pointed out, this poisons the use of 'break' when this is used inside a loop, as it now breaks the scope of the QEMU_WITH_LOCK instead of the outer loop). > It's possible to use QemuLockGuard also with a spinlock or a > CoMutex. However, it is _not_ possible to return a QemuLockGuard > since C doesn't have an equivalent of C++'s "move semantics", so > there are other "constructor" macros such as QEMU_ADOPT_LOCK > and QEMU_TAKEN_LOCK. > > On the positive side, I checked that the entire abstraction > is removed by the compiler, the generated code is more or less > the same. Also, it would let us for example change block/curl.c > to use a CoQueue instead of a home-grown list+QemuMutex. > > However, I am still not sure about the readability, and it doesn't play > well with another common idiom in QEMU, which is to wrap global mutexes > with function such as > > static void block_job_lock(void) > { > qemu_mutex_lock(&block_job_mutex); > } > > static void block_job_unlock(void) > { > qemu_mutex_unlock(&block_job_mutex); > } > > So I'm a bit underwhelmed by this experiment. Other opinions? The semantics you list here: > QEMU_WITH_LOCK(QemuMutex, guard_name, &some_mutex) { > ... > } are slightly different from the semantics in nbdkit: { ACQUIRE_LOCK_FOR_CURRENT_SCOPE(&some_lock); ... } In that your version requires the user to supply the scope after your macro, instead of using your macro within the scope. But I guess that's because you added other helpers like QEMU_WITH_ADOPTED_LOCK, QEMU_RETURN_LOCK, and QEMU_TAKEN_LOCK, where you have multiple possibilities for which state the lock should be in. Is it worth playing around with the user providing the scope around your macros, instead of using your macro to introduce the scope? -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
[Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
This is an attempt to make a C API that resembles the C++ std::unique_lock (mostly untested). The idea is that you can write QEMU_LOCK_GUARD(QemuMutex, guard_name, &some_mutex); instead of qemu_mutex_lock(&some_mutex); ... out: qemu_mutex_unlock(&some_mutex); and the mutex will be unlocked on all exit paths. In C++ that would be "std::unique_lock guard_name(some_mutex);". Likewise, QEMU_WITH_LOCK(QemuMutex, guard_name, &some_mutex) { ... } is the same as qemu_mutex_lock(&some_mutex); ... qemu_mutex_unlock(&some_mutex); except that any returns within the region will unlock the mutex. It's possible to use QemuLockGuard also with a spinlock or a CoMutex. However, it is _not_ possible to return a QemuLockGuard since C doesn't have an equivalent of C++'s "move semantics", so there are other "constructor" macros such as QEMU_ADOPT_LOCK and QEMU_TAKEN_LOCK. On the positive side, I checked that the entire abstraction is removed by the compiler, the generated code is more or less the same. Also, it would let us for example change block/curl.c to use a CoQueue instead of a home-grown list+QemuMutex. However, I am still not sure about the readability, and it doesn't play well with another common idiom in QEMU, which is to wrap global mutexes with function such as static void block_job_lock(void) { qemu_mutex_lock(&block_job_mutex); } static void block_job_unlock(void) { qemu_mutex_unlock(&block_job_mutex); } So I'm a bit underwhelmed by this experiment. Other opinions? Paolo Paolo Bonzini (5): compiler: add a helper for C99 inline functions lock-guard: add scoped lock implementation qemu-timer: convert to use lock guards qht: convert to use lock guards thread-pool: convert to use lock guards include/qemu/compiler.h | 15 +++ include/qemu/coroutine.h | 4 ++ include/qemu/lock-guard.h | 99 +++ include/qemu/thread.h | 7 util/Makefile.objs| 1 + util/qemu-thread.c| 17 util/qemu-timer.c | 84 util/qht.c| 59 ++-- util/thread-pool.c| 26 ++--- 9 files changed, 225 insertions(+), 87 deletions(-) create mode 100644 include/qemu/lock-guard.h create mode 100644 util/qemu-thread.c -- 2.14.3