From 2ca9ed527e8a18ff402e036174b2b003460fdf06 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 23 May 2012 13:13:56 +0000 Subject: [PATCH] * fhandler.h (refcnt): Add i interlocked. Explain why. * winbase.h (ilockadd): New function. (InterlockedAdd): Define as ilockadd. --- winsup/cygwin/ChangeLog | 6 ++++++ winsup/cygwin/fhandler.h | 6 +++++- winsup/cygwin/winbase.h | 19 ++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index c87f6016e..264507fcf 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,9 @@ +2012-05-23 Corinna Vinschen + + * fhandler.h (refcnt): Add i interlocked. Explain why. + * winbase.h (ilockadd): New function. + (InterlockedAdd): Define as ilockadd. + 2012-05-22 Corinna Vinschen * devices.in: Fix native name of /dev/kmem. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 18e829aa6..84f6e4c3f 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -185,7 +185,11 @@ class fhandler_base long refcnt(long i = 0) { debug_only_printf ("%p, %s, i %d, refcnt %ld", this, get_name (), i, _refcnt + i); - return _refcnt += i; + /* This MUST be an interlocked operation. If multiple threads access the + same descriptor in quick succession, a context switch can interrupt + the += operation and we wrongly end up with a refcnt of 0 in the + cygheap_fdget destructor. */ + return i ? InterlockedAdd (&_refcnt, i) : _refcnt; } class fhandler_base *archetype; int usecount; diff --git a/winsup/cygwin/winbase.h b/winsup/cygwin/winbase.h index 00c71a923..4d92a9261 100644 --- a/winsup/cygwin/winbase.h +++ b/winsup/cygwin/winbase.h @@ -1,6 +1,6 @@ /* winbase.h - Copyright 2002, 2003, 2004, 2008 Red Hat, Inc. + Copyright 2002, 2003, 2004, 2008, 2012 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for @@ -11,6 +11,21 @@ details. */ #ifndef _WINBASE2_H #define _WINBASE2_H +/* For some unknown reason, InterlockedAdd is only supported on Itanium + when using the Windows headers. Fortunately we're not restricted to the + Windows headers :) */ +extern __inline__ long +ilockadd (volatile long *m, long value) +{ + register int __res; + __asm__ __volatile__ ("\n\ + movl %3,%0\n\ + lock xadd %0,%1\n\ + addl %3,%0\n\ + ": "=&r" (__res), "=m" (*m): "m" (*m), "r" (value): "cc"); + return __res; +} + extern __inline__ long ilockincr (volatile long *m) { @@ -65,6 +80,8 @@ ilockcmpexch (volatile long *t, long v, long c) }); } +#undef InterlockedAdd +#define InterlockedAdd ilockadd #undef InterlockedIncrement #define InterlockedIncrement ilockincr #undef InterlockedDecrement