[PATCH 1/3] cairo_rwlock: introduce rwl ock.

Zhigang Gong <[email protected]>
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
Here is a scenario which make us to introduce rwlock.
1. One thread(A) is rendering to a surface which has a snapshot attached.
2. Some other threads(B...) are replaying recording surfaces which has the
snapshot of the surface which is being rendered in thread 1.

If thread B already started the replaying, and already get the source
by using _cairo_surface_snapshot_source, then before the thread B finish
its accessing to the source surface, the thread A start to rendering to
the source surface. Although thread A will trigger a COW, but it's too
late, as thread B already got the original surface pointer, thus the
race ocurrs here, both B is reading and A is writing to the same area
concurrently.

To fix this issue, we need to use write lock at thread B, and use read
lock at thread B to avoid the possible race condtion.

Currently, we only implement pthread_rw_lock if the system supports
pthread. Otherwise, we degrade the rw_lock to a normal lock.

Signed-off-by: Zhigang Gong <[email protected]>
---
 build/configure.ac.pthread      |   13 ++++
 src/Makefile.sources            |    4 +
 src/cairo-rwlock-impl-private.h |  135 +++++++++++++++++++++++++++++++++++++++
 src/cairo-rwlock-private.h      |   51 +++++++++++++++
 src/cairo-rwlock-type-private.h |   89 +++++++++++++++++++++++++
 src/cairo-rwlock.c              |   56 ++++++++++++++++
 6 files changed, 348 insertions(+), 0 deletions(-)
 create mode 100644 src/cairo-rwlock-impl-private.h
 create mode 100644 src/cairo-rwlock-private.h
 create mode 100644 src/cairo-rwlock-type-private.h
 create mode 100644 src/cairo-rwlock.c

diff --git a/build/configure.ac.pthread b/build/configure.ac.pthread
index 29c930d..72ed03a 100644
--- a/build/configure.ac.pthread
+++ b/build/configure.ac.pthread
@@ -76,6 +76,19 @@ int test_mutex_attr (void)
 	x |= pthread_mutex_destroy (&mutex);
 	x |= pthread_mutexattr_destroy (&attr);
 	return x;
+}
+
+pthread_rwlock_t test_rwlock_initializer = PTHREAD_RWLOCK_INITIALIZER;
+int test_rwlock (void)
+{
+	int x = 0;
+	pthread_rwlock_t rwlock;
+	x |= pthread_rwlock_init(&rwlock, NULL);
+	x |= pthread_rwlock_wrlock(&rwlock);
+	x |= pthread_rwlock_unlock(&rwlock);
+	x |= pthread_rwlock_rdlock(&rwlock);
+	x |= pthread_rwlock_unlock(&rwlock);
+	x |= pthread_rwlock_destroy(&rwlock);
 }])
 
 dnl -----------------------------------------------------------------------
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f487fc1..198c276 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -91,6 +91,9 @@ cairo_private = \
 	cairo-mutex-list-private.h \
 	cairo-mutex-private.h \
 	cairo-mutex-type-private.h \
+	cairo-rwlock-private.h \
+	cairo-rwlock-impl-private.h \
+	cairo-rwlock-type-private.h \
 	cairo-output-stream-private.h \
 	cairo-paginated-private.h \
 	cairo-paginated-surface-private.h \
@@ -181,6 +184,7 @@ cairo_sources = \
 	cairo-misc.c \
 	cairo-mono-scan-converter.c \
 	cairo-mutex.c \
+	cairo-rwlock.c \
 	cairo-no-compositor.c \
 	cairo-observer.c \
 	cairo-output-stream.c \
diff --git a/src/cairo-rwlock-impl-private.h b/src/cairo-rwlock-impl-private.h
new file mode 100644
index 0000000..67a8fc9
--- /dev/null
+++ b/src/cairo-rwlock-impl-private.h
@@ -0,0 +1,135 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005,2007 Red Hat, Inc.
+ * Copyright © 2007 Mathias Hasselmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * 	Zhigang Gong <[email protected]>
+ */
+
+#ifndef CAIRO_RWLOCK_IMPL_PRIVATE_H
+#define CAIRO_RWLOCK_IMPL_PRIVATE_H
+#include "cairo.h"
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* A fully qualified no-operation statement */
+#define CAIRO_RWLOCK_IMPL_NOOP	do {/*no-op*/} while (0)
+/* And one that evaluates its argument once */
+#define CAIRO_RWLOCK_IMPL_NOOP1(expr)        do { (void)(expr); } while (0)
+/* Note: 'if (expr) {}' is an alternative to '(void)(expr);' that will 'use' the
+ * result of __attribute__((warn_used_result)) functions. */
+
+#if CAIRO_NO_RWLOCK
+
+/* No rwlocks */
+
+  typedef int cairo_rwlock_impl_t;
+
+# define CAIRO_RWLOCK_IMPL_NO 1
+# define CAIRO_RWLOCK_IMPL_LOCK(rwlock) CAIRO_RWLOCK_IMPL_NOOP1(rwlock)
+# define CAIRO_RWLOCK_IMPL_UNLOCK(rwlock) CAIRO_RWLOCK_IMPL_NOOP1(rwlock)
+# define CAIRO_RWLOCK_IMPL_NIL_INITIALIZER 0
+
+#elif defined(_WIN32) /******************************************************/
+
+#define WIN32_LEAN_AND_MEAN
+/* We require Windows 2000 features such as ETO_PDY */
+#if !defined(WINVER) || (WINVER < 0x0500)
+# define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+# define _WIN32_WINNT 0x0500
+#endif
+
+# include <windows.h>
+
+  typedef CRITICAL_SECTION cairo_rwlock_impl_t;
+
+# define CAIRO_RWLOCK_IMPL_WIN32 1
+# define CAIRO_RWLOCK_IMPL_RDLOCK(rwlock) EnterCriticalSection (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_WRLOCK(rwlock) EnterCriticalSection (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_UNLOCK(rwlock) LeaveCriticalSection (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_INIT(rwlock) InitializeCriticalSection (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_FINI(rwlock) DeleteCriticalSection (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
+
+#elif defined __OS2__ /******************************************************/
+
+# define INCL_BASE
+# define INCL_PM
+# include <os2.h>
+
+  typedef HMTX cairo_rwlock_impl_t;
+
+# define CAIRO_RWLOCK_IMPL_OS2 1
+# define CAIRO_RWLOCK_IMPL_RDLOCK(rwlock) DosRequestMutexSem(rwlock, SEM_INDEFINITE_WAIT)
+# define CAIRO_RWLOCK_IMPL_WRLOCK(rwlock) DosRequestMutexSem(rwlock, SEM_INDEFINITE_WAIT)
+# define CAIRO_RWLOCK_IMPL_UNLOCK(rwlock) DosReleaseMutexSem(rwlock)
+# define CAIRO_RWLOCK_IMPL_INIT(rwlock) DosCreateMutexSem (NULL, &(rwlock), 0L, FALSE)
+# define CAIRO_RWLOCK_IMPL_FINI(rwlock) DosCloseMutexSem (rwlock)
+# define CAIRO_RWLOCK_IMPL_NIL_INITIALIZER 0
+
+#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
+
+  typedef BLocker* cairo_rwlock_impl_t;
+
+# define CAIRO_RWLOCK_IMPL_BEOS 1
+# define CAIRO_RWLOCK_IMPL_RDLOCK(rwlock) (rwlock)->Lock()
+# define CAIRO_RWLOCK_IMPL_WRLOCK(rwlock) (rwlock)->Lock()
+# define CAIRO_RWLOCK_IMPL_UNLOCK(rwlock) (rwlock)->Unlock()
+# define CAIRO_RWLOCK_IMPL_INIT(rwlock) (rwlock) = new BLocker()
+# define CAIRO_RWLOCK_IMPL_FINI(rwlock) delete (rwlock)
+# define CAIRO_RWLOCK_IMPL_NIL_INITIALIZER NULL
+
+#elif CAIRO_HAS_PTHREAD /* and finally if there are no native rwlocks ********/
+
+# include <pthread.h>
+  typedef pthread_rwlock_t cairo_rwlock_impl_t;
+
+# define CAIRO_RWLOCK_IMPL_PTHREAD 1
+# define CAIRO_RWLOCK_IMPL_INIT(rwlock) pthread_rwlock_init (&(rwlock), NULL)
+# define CAIRO_RWLOCK_IMPL_RDLOCK(rwlock) pthread_rwlock_rdlock (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_WRLOCK(rwlock) pthread_rwlock_wrlock (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_UNLOCK(rwlock) pthread_rwlock_unlock (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_FINI(rwlock) pthread_rwlock_destroy (&(rwlock))
+# define CAIRO_RWLOCK_IMPL_NIL_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
+
+#else /**********************************************************************/
+
+# error "XXX: No rwlock implementation found.  Cairo will not work with multiple threads.  Define CAIRO_NO_RWLOCK to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
+
+#endif
+
+#endif
diff --git a/src/cairo-rwlock-private.h b/src/cairo-rwlock-private.h
new file mode 100644
index 0000000..1ca361d
--- /dev/null
+++ b/src/cairo-rwlock-private.h
@@ -0,0 +1,51 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005,2007 Red Hat, Inc.
+ * Copyright © 2007 Mathias Hasselmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * 	Zhigang Gong <[email protected]>
+ */
+
+#ifndef CAIRO_RWLOCK_PRIVATE_H
+#define CAIRO_RWLOCK_PRIVATE_H
+
+#include "cairo-rwlock-type-private.h"
+
+CAIRO_BEGIN_DECLS
+
+cairo_private void _cairo_rwlock_initialize (void);
+cairo_private void _cairo_rwlock_finalize (void);
+
+CAIRO_END_DECLS
+
+#endif
diff --git a/src/cairo-rwlock-type-private.h b/src/cairo-rwlock-type-private.h
new file mode 100644
index 0000000..f60fa6a
--- /dev/null
+++ b/src/cairo-rwlock-type-private.h
@@ -0,0 +1,89 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005,2007 Red Hat, Inc.
+ * Copyright © 2007 Mathias Hasselmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * 	Zhigang Gong <[email protected]>
+ */
+
+#ifndef CAIRO_RWLOCK_TYPE_PRIVATE_H
+#define CAIRO_RWLOCK_TYPE_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-rwlock-impl-private.h"
+
+/* Only the following four are mandatory at this point */
+#ifndef CAIRO_RWLOCK_IMPL_RDLOCK
+# error "CAIRO_RWLOCK_IMPL_RDLOCK not defined.  Check cairo-rwlock-impl-private.h."
+#endif
+#ifndef CAIRO_RWLOCK_IMPL_WRLOCK
+# error "CAIRO_RWLOCK_IMPL_WRLOCK not defined.  Check cairo-rwlock-impl-private.h."
+#endif
+#ifndef CAIRO_RWLOCK_IMPL_UNLOCK
+# error "CAIRO_RWLOCK_IMPL_UNLOCK not defined.  Check cairo-rwlock-impl-private.h."
+#endif
+#ifndef CAIRO_RWLOCK_IMPL_NIL_INITIALIZER
+# error "CAIRO_RWLOCK_IMPL_NIL_INITIALIZER not defined.  Check cairo-rwlock-impl-private.h."
+#endif
+
+
+/* Make sure everything we want is defined */
+#ifndef CAIRO_RWLOCK_IMPL_INIT
+# error "CAIRO_RWLOCK_IMPL_INIT not defined"
+#endif
+#ifndef CAIRO_RWLOCK_IMPL_FINI
+# error "CAIRO_RWLOCK_IMPL_FINI not defined"
+#endif
+#ifndef CAIRO_RWLOCK_IMPL_NIL_INITIALIZER
+# error "CAIRO_RWLOCK_IMPL_NIL_INITIALIZER not defined"
+#endif
+
+/* Public interface. */
+
+# define cairo_rwlock_t			cairo_rwlock_impl_t
+
+#define CAIRO_RWLOCK_RDLOCK		CAIRO_RWLOCK_IMPL_RDLOCK
+#define CAIRO_RWLOCK_WRLOCK		CAIRO_RWLOCK_IMPL_WRLOCK
+#define CAIRO_RWLOCK_UNLOCK		CAIRO_RWLOCK_IMPL_UNLOCK
+#define CAIRO_RWLOCK_INIT		CAIRO_RWLOCK_IMPL_INIT
+#define CAIRO_RWLOCK_FINI		CAIRO_RWLOCK_IMPL_FINI
+#define CAIRO_RWLOCK_NIL_INITIALIZER	CAIRO_RWLOCK_IMPL_NIL_INITIALIZER
+
+#ifndef CAIRO_RWLOCK_IS_LOCKED
+# define CAIRO_RWLOCK_IS_LOCKED(name) 1
+#endif
+#ifndef CAIRO_RWLOCK_IS_UNLOCKED
+# define CAIRO_RWLOCK_IS_UNLOCKED(name) 1
+#endif
+
+#endif
diff --git a/src/cairo-rwlock.c b/src/cairo-rwlock.c
new file mode 100644
index 0000000..492716e
--- /dev/null
+++ b/src/cairo-rwlock.c
@@ -0,0 +1,56 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Mathias Hasselmann
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * Contributor(s):
+ *	Mathias Hasselmann <[email protected]>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-rwlock-private.h"
+
+static int _cairo_rwlock_initialized = 0;
+
+void _cairo_rwlock_initialize (void)
+{
+    if (_cairo_rwlock_initialized)
+        return;
+
+    _cairo_rwlock_initialized = TRUE;
+
+}
+
+void _cairo_rwlock_finalize (void)
+{
+    if (!_cairo_rwlock_initialized)
+        return;
+
+    _cairo_rwlock_initialized = FALSE;
+
+}
-- 
1.7.4.4

--
cairo mailing list
[email protected]
http://lists.cairographics.org/mailman/listinfo/cairo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.