1d012387afef0ba02185ebe27bc6bb15551912e92Havoc Pennington/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
25886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington/* dbus-sysdeps-pthread.c Implements threads using pthreads (internal to libdbus)
35886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington *
45886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
55886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington *
65886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * Licensed under the Academic Free License version 2.1
75886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington *
85886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * This program is free software; you can redistribute it and/or modify
95886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * it under the terms of the GNU General Public License as published by
105886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * the Free Software Foundation; either version 2 of the License, or
115886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * (at your option) any later version.
125886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington *
135886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * This program is distributed in the hope that it will be useful,
145886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * but WITHOUT ANY WARRANTY; without even the implied warranty of
155886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
165886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * GNU General Public License for more details.
175886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington *
185886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * You should have received a copy of the GNU General Public License
195886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington * along with this program; if not, write to the Free Software
205baf2f856a9c6625993234855b07680da1c8916fTobias Mueller * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
215886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington *
225886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington */
235886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
24dbecdeabb20e0ce11121819c63373f0afba57c58Marcus Brinkmann#include <config.h>
255886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington#include "dbus-internals.h"
265886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington#include "dbus-sysdeps.h"
275886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington#include "dbus-threads.h"
285886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
295886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington#include <sys/time.h>
305886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington#include <pthread.h>
31bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington#include <string.h>
325886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
3343b944a0a6ea48e8a8b06ae3e638299f591cde8dHavoc Pennington#ifdef HAVE_ERRNO_H
3443b944a0a6ea48e8a8b06ae3e638299f591cde8dHavoc Pennington#include <errno.h>
3543b944a0a6ea48e8a8b06ae3e638299f591cde8dHavoc Pennington#endif
3643b944a0a6ea48e8a8b06ae3e638299f591cde8dHavoc Pennington
37ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#include <config.h>
38ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters
39ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters/* Whether we have a "monotonic" clock; i.e. a clock not affected by
40ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters * changes in system time.
41ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters * This is initialized once in check_monotonic_clock below.
42ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters * https://bugs.freedesktop.org/show_bug.cgi?id=18121
43ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters */
44ae24bb35e2ee3ecde990f55852982b573754ec43Colin Waltersstatic dbus_bool_t have_monotonic_clock = 0;
45ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters
46bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Penningtontypedef struct {
47fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington  pthread_mutex_t lock; /**< lock protecting count field */
48fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington  volatile int count;   /**< count of how many times lock holder has recursively locked */
49fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington  volatile pthread_t holder; /**< holder of the lock if count >0,
50fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington                                valid but arbitrary thread if count
51fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington                                has ever been >0, uninitialized memory
52fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington                                if count has never been >0 */
53bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington} DBusMutexPThread;
54bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
55bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Penningtontypedef struct {
56fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington  pthread_cond_t cond; /**< the condition */
57bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington} DBusCondVarPThread;
58bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
59bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington#define DBUS_MUTEX(m)         ((DBusMutex*) m)
60bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington#define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m)
61bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
62bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington#define DBUS_COND_VAR(c)         ((DBusCondVar*) c)
63bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington#define DBUS_COND_VAR_PTHREAD(c) ((DBusCondVarPThread*) c)
64bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
65bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
66fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington#ifdef DBUS_DISABLE_ASSERT
67eaefe03a8891b84e3f9e1f99f9098d65567e3092Havoc Pennington/* (tmp != 0) is a no-op usage to silence compiler */
68eaefe03a8891b84e3f9e1f99f9098d65567e3092Havoc Pennington#define PTHREAD_CHECK(func_name, result_or_call)    \
69eaefe03a8891b84e3f9e1f99f9098d65567e3092Havoc Pennington    do { int tmp = (result_or_call); if (tmp != 0) {;} } while (0)
70fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington#else
71bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington#define PTHREAD_CHECK(func_name, result_or_call) do {                                  \
72bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    int tmp = (result_or_call);                                                        \
73bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    if (tmp != 0) {                                                                    \
74bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington      _dbus_warn_check_failed ("pthread function %s failed with %d %s in %s\n",        \
75bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington                               func_name, tmp, strerror(tmp), _DBUS_FUNCTION_NAME);    \
76bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    }                                                                                  \
77bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington} while (0)
78fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington#endif /* !DBUS_DISABLE_ASSERT */
79fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington
805886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic DBusMutex*
815886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_mutex_new (void)
825886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
83bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusMutexPThread *pmutex;
84bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  int result;
855886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
86bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  pmutex = dbus_new (DBusMutexPThread, 1);
87bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  if (pmutex == NULL)
885886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    return NULL;
89bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
90bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  result = pthread_mutex_init (&pmutex->lock, NULL);
91bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
92bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  if (result == ENOMEM || result == EAGAIN)
935886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    {
94bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington      dbus_free (pmutex);
955886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington      return NULL;
965886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    }
97bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  else
98bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    {
99bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington      PTHREAD_CHECK ("pthread_mutex_init", result);
100bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    }
1015886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
102fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  /* Only written */
103fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  pmutex->count = 0;
104fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
105fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  /* There's no portable way to have a "null" pthread afaik so we
106fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   * can't set pmutex->holder to anything sensible.  We only access it
107fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   * once the lock is held (which means we've set it).
108fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   */
109fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
110bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  return DBUS_MUTEX (pmutex);
1115886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
1125886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
1135886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic void
1145886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_mutex_free (DBusMutex *mutex)
1155886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
116bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
117fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
118fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pmutex->count == 0);
119bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
120bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&pmutex->lock));
121bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
122bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  dbus_free (pmutex);
1235886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
1245886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
125fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Penningtonstatic void
1265886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_mutex_lock (DBusMutex *mutex)
1275886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
128bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
129fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  pthread_t self = pthread_self ();
130fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
131fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  /* If the count is > 0 then someone had the lock, maybe us. If it is
132fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   * 0, then it might immediately change right after we read it,
133fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   * but it will be changed by another thread; i.e. if we read 0,
134fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   * we assume that this thread doesn't have the lock.
135fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   *
136fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   * Not 100% sure this is safe, but ... seems like it should be.
137fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington   */
138fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  if (pmutex->count == 0)
139fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington    {
140fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      /* We know we don't have the lock; someone may have the lock. */
141fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
142fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
143fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
144fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington      /* We now have the lock. Count must be 0 since it must be 0 when
145fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington       * the lock is released by another thread, and we just now got
146fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington       * the lock.
147fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington       */
148fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      _dbus_assert (pmutex->count == 0);
149fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
150fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      pmutex->holder = self;
151fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      pmutex->count = 1;
152fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington    }
153fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  else
154fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington    {
155fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      /* We know someone had the lock, possibly us. Thus
156fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington       * pmutex->holder is not pointing to junk, though it may not be
157fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington       * the lock holder anymore if the lock holder is not us.  If the
158fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington       * lock holder is us, then we definitely have the lock.
159fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington       */
160fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
161fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      if (pthread_equal (pmutex->holder, self))
162fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington        {
163fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington          /* We already have the lock. */
164fd27857e31dc6bd7b78ddddbb6ef3f1162ee0b88Havoc Pennington          _dbus_assert (pmutex->count > 0);
165fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington        }
166fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      else
167fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington        {
168fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington          /* Wait for the lock */
169fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington          PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
170c0dbd2a2b5ce42612b1bffe778d6127682cddb45Thiago Macieira	  pmutex->holder = self;
171fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington          _dbus_assert (pmutex->count == 0);
172fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington        }
173fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
174fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington      pmutex->count += 1;
175fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington    }
1765886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
1775886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
178fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Penningtonstatic void
1795886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_mutex_unlock (DBusMutex *mutex)
1805886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
181bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
182bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
183fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pmutex->count > 0);
184fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
185fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  pmutex->count -= 1;
186bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
187fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  if (pmutex->count == 0)
188fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington    PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&pmutex->lock));
189fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
190fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  /* We leave pmutex->holder set to ourselves, its content is undefined if count is 0 */
1915886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
1925886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
1935886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic DBusCondVar *
1945886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_condvar_new (void)
1955886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
196bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusCondVarPThread *pcond;
197ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  pthread_condattr_t attr;
198bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  int result;
1995886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
200bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  pcond = dbus_new (DBusCondVarPThread, 1);
201bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  if (pcond == NULL)
2025886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    return NULL;
203bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
204ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  pthread_condattr_init (&attr);
205ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#ifdef HAVE_MONOTONIC_CLOCK
206ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  if (have_monotonic_clock)
207ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters    pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
208ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#endif
209ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters
210ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  result = pthread_cond_init (&pcond->cond, &attr);
211ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  pthread_condattr_destroy (&attr);
212bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
213bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  if (result == EAGAIN || result == ENOMEM)
2145886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    {
215bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington      dbus_free (pcond);
2165886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington      return NULL;
2175886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    }
218bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  else
219bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    {
220bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington      PTHREAD_CHECK ("pthread_cond_init", result);
221bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    }
222bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
223bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  return DBUS_COND_VAR (pcond);
2245886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
2255886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
2265886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic void
2275886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_condvar_free (DBusCondVar *cond)
228bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington{
229bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
230bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
231bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&pcond->cond));
232bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
233bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  dbus_free (pcond);
2345886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
2355886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
2365886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic void
2375886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_condvar_wait (DBusCondVar *cond,
238bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington                            DBusMutex   *mutex)
2395886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
240bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
241bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
242fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  int old_count;
243bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
244fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pmutex->count > 0);
245fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));
246fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
247fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  old_count = pmutex->count;
248c0dbd2a2b5ce42612b1bffe778d6127682cddb45Thiago Macieira  pmutex->count = 0;		/* allow other threads to lock */
249bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&pcond->cond, &pmutex->lock));
250fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pmutex->count == 0);
251c0dbd2a2b5ce42612b1bffe778d6127682cddb45Thiago Macieira  pmutex->holder = pthread_self(); /* other threads may have locked the mutex in the meantime */
252537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie
253537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie  /* The order of this line and the above line is important.
254537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie   * See the comments below at the end of _dbus_pthread_condvar_wait_timeout
255537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie   */
256537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie  pmutex->count = old_count;
2575886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
2585886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
2595886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic dbus_bool_t
2605886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_condvar_wait_timeout (DBusCondVar               *cond,
261bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington                                    DBusMutex                 *mutex,
262bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington                                    int                        timeout_milliseconds)
2635886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
264bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
265bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
2665886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  struct timeval time_now;
2675886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  struct timespec end_time;
2685886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  int result;
269fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  int old_count;
270fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
271fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pmutex->count > 0);
272fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));
273ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters
274ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#ifdef HAVE_MONOTONIC_CLOCK
275ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  if (have_monotonic_clock)
276ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters    {
277ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters      struct timespec monotonic_timer;
278ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters      clock_gettime (CLOCK_MONOTONIC,&monotonic_timer);
279ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters      time_now.tv_sec = monotonic_timer.tv_sec;
280ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters      time_now.tv_usec = monotonic_timer.tv_nsec / 1000;
281ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters    }
282ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  else
283ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters    /* This else falls through to gettimeofday */
284ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#endif
2855886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  gettimeofday (&time_now, NULL);
2865886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
2875886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
2885886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
2895886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  if (end_time.tv_nsec > 1000*1000*1000)
2905886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    {
2915886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington      end_time.tv_sec += 1;
2925886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington      end_time.tv_nsec -= 1000*1000*1000;
2935886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington    }
294bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
295fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  old_count = pmutex->count;
296fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  pmutex->count = 0;
297bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  result = pthread_cond_timedwait (&pcond->cond, &pmutex->lock, &end_time);
298fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
299bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  if (result != ETIMEDOUT)
300bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    {
301bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington      PTHREAD_CHECK ("pthread_cond_timedwait", result);
302bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington    }
303fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington
304fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_assert (pmutex->count == 0);
305c0dbd2a2b5ce42612b1bffe778d6127682cddb45Thiago Macieira  pmutex->holder = pthread_self(); /* other threads may have locked the mutex in the meantime */
306537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie
307537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie  /* restore to old count after setting the owner back to self,
308537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie   * If reversing this line with above line, the previous owner thread could
309537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie   * get into the mutex without proper locking by passing the lock owner check.
310537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie   */
311537eaff5de9aace3348436166d4cde7adc1e488eMatthew Xie  pmutex->count = old_count;
3125886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
3135886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  /* return true if we did not time out */
3145886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  return result != ETIMEDOUT;
3155886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
3165886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
3175886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic void
3185886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_condvar_wake_one (DBusCondVar *cond)
3195886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
320bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
321bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
322bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&pcond->cond));
3235886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
3245886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
3255886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic void
3265886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_pthread_condvar_wake_all (DBusCondVar *cond)
3275886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
328bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
329bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington
330bdbbf46ca88ac43bec9c36909990730d102983c5Havoc Pennington  PTHREAD_CHECK ("pthread_cond_broadcast", pthread_cond_broadcast (&pcond->cond));
3315886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
3325886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
3335886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtonstatic const DBusThreadFunctions pthread_functions =
3345886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
335fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK |
336fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK |
337fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK |
338fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK |
3395886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
3405886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
3415886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
3425886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
3435886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
3445886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
345fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  NULL, NULL, NULL, NULL,
3465886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  _dbus_pthread_condvar_new,
3475886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  _dbus_pthread_condvar_free,
3485886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  _dbus_pthread_condvar_wait,
3495886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  _dbus_pthread_condvar_wait_timeout,
3505886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  _dbus_pthread_condvar_wake_one,
351fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_pthread_condvar_wake_all,
352fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_pthread_mutex_new,
353fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_pthread_mutex_free,
354fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_pthread_mutex_lock,
355fbfec98d0f3ad5232dd6cbd63acbdd008acf2578Havoc Pennington  _dbus_pthread_mutex_unlock
3565886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington};
3575886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington
358ae24bb35e2ee3ecde990f55852982b573754ec43Colin Waltersstatic void
359ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walterscheck_monotonic_clock (void)
360ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters{
361ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#ifdef HAVE_MONOTONIC_CLOCK
362ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  struct timespec dummy;
363ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0)
364ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters    have_monotonic_clock = TRUE;
365ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters#endif
366ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters}
367ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters
3685886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Penningtondbus_bool_t
3695886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington_dbus_threads_init_platform_specific (void)
3705886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington{
371ae24bb35e2ee3ecde990f55852982b573754ec43Colin Walters  check_monotonic_clock ();
3725886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington  return dbus_threads_init (&pthread_functions);
3735886f5326da2dbe8f1a7c97736d544fa4cef169bHavoc Pennington}
374