1/*
2 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "condition_variable_posix.h"
12
13#if defined(WEBRTC_LINUX)
14#include <ctime>
15#else
16#include <sys/time.h>
17#endif
18
19#include <errno.h>
20
21#include "critical_section_posix.h"
22
23namespace webrtc {
24ConditionVariableWrapper* ConditionVariablePosix::Create()
25{
26    ConditionVariablePosix* ptr = new ConditionVariablePosix;
27    if (!ptr)
28    {
29        return NULL;
30    }
31
32    const int error = ptr->Construct();
33    if (error)
34    {
35        delete ptr;
36        return NULL;
37    }
38
39    return ptr;
40}
41
42ConditionVariablePosix::ConditionVariablePosix()
43{
44}
45
46int ConditionVariablePosix::Construct()
47{
48    int result = 0;
49#ifdef WEBRTC_CLOCK_TYPE_REALTIME
50    result = pthread_cond_init(&_cond, NULL);
51#else
52    pthread_condattr_t condAttr;
53    result = pthread_condattr_init(&condAttr);
54    if (result != 0)
55    {
56        return -1;
57    }
58    result = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
59    if (result != 0)
60    {
61        return -1;
62    }
63    result = pthread_cond_init(&_cond, &condAttr);
64    if (result != 0)
65    {
66        return -1;
67    }
68    result = pthread_condattr_destroy(&condAttr);
69    if (result != 0)
70    {
71        return -1;
72    }
73#endif
74    return 0;
75}
76
77ConditionVariablePosix::~ConditionVariablePosix()
78{
79    pthread_cond_destroy(&_cond);
80}
81
82void ConditionVariablePosix::SleepCS(CriticalSectionWrapper& critSect)
83{
84    CriticalSectionPosix* cs = reinterpret_cast<CriticalSectionPosix*>(
85                                   &critSect);
86    pthread_cond_wait(&_cond, &cs->_mutex);
87}
88
89
90bool
91ConditionVariablePosix::SleepCS(
92    CriticalSectionWrapper& critSect,
93    unsigned long maxTimeInMS)
94{
95    const unsigned long INFINITE =  0xFFFFFFFF;
96
97    const int MILLISECONDS_PER_SECOND      = 1000;
98#ifndef WEBRTC_LINUX
99    const int MICROSECONDS_PER_MILLISECOND = 1000;
100#endif
101    const int NANOSECONDS_PER_SECOND       = 1000000000;
102    const int NANOSECONDS_PER_MILLISECOND  = 1000000;
103
104    CriticalSectionPosix* cs = reinterpret_cast<CriticalSectionPosix*>(
105                                   &critSect);
106
107    if (maxTimeInMS != INFINITE)
108    {
109        timespec ts;
110#ifndef WEBRTC_MAC
111#ifdef WEBRTC_CLOCK_TYPE_REALTIME
112        clock_gettime(CLOCK_REALTIME, &ts);
113#else
114        clock_gettime(CLOCK_MONOTONIC, &ts);
115#endif
116#else
117        struct timeval tv;
118        gettimeofday(&tv, 0);
119        ts.tv_sec  = tv.tv_sec;
120        ts.tv_nsec = tv.tv_usec * MICROSECONDS_PER_MILLISECOND;
121#endif
122
123        ts.tv_sec += maxTimeInMS / MILLISECONDS_PER_SECOND;
124        ts.tv_nsec += (maxTimeInMS - ((maxTimeInMS / MILLISECONDS_PER_SECOND)*
125                      MILLISECONDS_PER_SECOND)) * NANOSECONDS_PER_MILLISECOND;
126
127        if (ts.tv_nsec >= NANOSECONDS_PER_SECOND)
128        {
129            ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
130            ts.tv_nsec %= NANOSECONDS_PER_SECOND;
131        }
132        const int res = pthread_cond_timedwait(&_cond, &cs->_mutex, &ts);
133        return (res == ETIMEDOUT) ? false : true;
134    }
135    else
136    {
137        pthread_cond_wait(&_cond, &cs->_mutex);
138        return true;
139    }
140}
141
142void ConditionVariablePosix::Wake()
143{
144    pthread_cond_signal(&_cond);
145}
146
147void ConditionVariablePosix::WakeAll()
148{
149    pthread_cond_broadcast(&_cond);
150}
151} // namespace webrtc
152