[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup))
From: |
Eric Blake |
Subject: |
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)) |
Date: |
Mon, 11 Dec 2017 08:11:44 -0600 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.4.0 |
On 12/11/2017 03:38 AM, Peter Maydell wrote:
> On 8 December 2017 at 19:40, Eric Blake <address@hidden> 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
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)), Eric Blake, 2017/12/08
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)), no-reply, 2017/12/11
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)), no-reply, 2017/12/11
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)), no-reply, 2017/12/11
Re: [Qemu-devel] [RFC PATCH 0/5] Scoped locks using attribute((cleanup)), Emilio G. Cota, 2017/12/11