summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog6
-rw-r--r--winsup/cygwin/fhandler.h6
-rw-r--r--winsup/cygwin/winbase.h19
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 <corinna@vinschen.de>
+
+ * fhandler.h (refcnt): Add i interlocked. Explain why.
+ * winbase.h (ilockadd): New function.
+ (InterlockedAdd): Define as ilockadd.
+
2012-05-22 Corinna Vinschen <corinna@vinschen.de>
* 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