[cairo] [PATCH 1/3] cairo_rwlock: introduce rwlock.

Zhigang Gong zhigang.gong at linux.intel.com
Fri May 25 02:13:47 PDT 2012


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 <zhigang.gong at linux.intel.com>
---
 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 <zhigang.gong at linux.intel.com>
+ */
+
+#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 <zhigang.gong at linux.intel.com>
+ */
+
+#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 <zhigang.gong at linux.intel.com>
+ */
+
+#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 <mathias.hasselmann at gmx.de>
+ */
+
+#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



More information about the cairo mailing list