OpenShot Audio Library | OpenShotAudio  0.3.1
juce_TimeSliceThread.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
27 {
28 }
29 
31 {
32  stopThread (2000);
33 }
34 
35 //==============================================================================
36 void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting)
37 {
38  if (client != nullptr)
39  {
40  const ScopedLock sl (listLock);
41  client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting);
42  clients.addIfNotAlreadyThere (client);
43  notify();
44  }
45 }
46 
48 {
49  const ScopedLock sl1 (listLock);
50 
51  // if there's a chance we're in the middle of calling this client, we need to
52  // also lock the outer lock..
53  if (clientBeingCalled == client)
54  {
55  const ScopedUnlock ul (listLock); // unlock first to get the order right..
56 
57  const ScopedLock sl2 (callbackLock);
58  const ScopedLock sl3 (listLock);
59 
60  clients.removeFirstMatchingValue (client);
61  }
62  else
63  {
64  clients.removeFirstMatchingValue (client);
65  }
66 }
67 
69 {
70  for (;;)
71  {
72  if (auto* c = getClient (0))
74  else
75  break;
76  }
77 }
78 
80 {
81  const ScopedLock sl (listLock);
82 
83  if (clients.contains (client))
84  {
85  client->nextCallTime = Time::getCurrentTime();
86  notify();
87  }
88 }
89 
91 {
92  return clients.size();
93 }
94 
96 {
97  const ScopedLock sl (listLock);
98  return clients[i];
99 }
100 
101 //==============================================================================
102 TimeSliceClient* TimeSliceThread::getNextClient (int index) const
103 {
104  Time soonest;
105  TimeSliceClient* client = nullptr;
106 
107  for (int i = clients.size(); --i >= 0;)
108  {
109  auto* c = clients.getUnchecked ((i + index) % clients.size());
110 
111  if (client == nullptr || c->nextCallTime < soonest)
112  {
113  client = c;
114  soonest = c->nextCallTime;
115  }
116  }
117 
118  return client;
119 }
120 
122 {
123  int index = 0;
124 
125  while (! threadShouldExit())
126  {
127  int timeToWait = 500;
128 
129  {
130  Time nextClientTime;
131  int numClients = 0;
132 
133  {
134  const ScopedLock sl2 (listLock);
135 
136  numClients = clients.size();
137  index = numClients > 0 ? ((index + 1) % numClients) : 0;
138 
139  if (auto* firstClient = getNextClient (index))
140  nextClientTime = firstClient->nextCallTime;
141  }
142 
143  if (numClients > 0)
144  {
145  auto now = Time::getCurrentTime();
146 
147  if (nextClientTime > now)
148  {
149  timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds());
150  }
151  else
152  {
153  timeToWait = index == 0 ? 1 : 0;
154 
155  const ScopedLock sl (callbackLock);
156 
157  {
158  const ScopedLock sl2 (listLock);
159  clientBeingCalled = getNextClient (index);
160  }
161 
162  if (clientBeingCalled != nullptr)
163  {
164  const int msUntilNextCall = clientBeingCalled->useTimeSlice();
165 
166  const ScopedLock sl2 (listLock);
167 
168  if (msUntilNextCall >= 0)
169  clientBeingCalled->nextCallTime = now + RelativeTime::milliseconds (msUntilNextCall);
170  else
171  clients.removeFirstMatchingValue (clientBeingCalled);
172 
173  clientBeingCalled = nullptr;
174  }
175  }
176  }
177  }
178 
179  if (timeToWait > 0)
180  wait (timeToWait);
181  }
182 }
183 
184 } // namespace juce
TimeSliceClient * getClient(int index) const
bool stopThread(int timeOutMilliseconds)
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
void notify() const
static RelativeTime milliseconds(int milliseconds) noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Definition: juce_Time.cpp:218
virtual int useTimeSlice()=0
bool threadShouldExit() const
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
TimeSliceThread(const String &threadName)
bool wait(int timeOutMilliseconds) const
void moveToFrontOfQueue(TimeSliceClient *clientToMove)