On 12/11/2017 03:38 AM, Peter Maydell wrote: > On 8 December 2017 at 19:40, Eric Blake <ebl...@redhat.com> 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 <stdio.h> #include <setjmp.h> #include <stdlib.h> 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