OpenShot Library | libopenshot-audio  0.2.0
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
int getNumClients() const
Returns the number of registered clients.
TimeSliceClient * getClient(int index) const
Returns one of the registered clients.
bool stopThread(int timeOutMilliseconds)
Attempts to stop the thread running.
~TimeSliceThread() override
Destructor.
virtual void run()=0
Must be implemented to perform the thread&#39;s actual code.
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
Removes a client from the list.
void notify() const
Wakes up the thread.
static RelativeTime milliseconds(int milliseconds) noexcept
Creates a new RelativeTime object representing a number of milliseconds.
The JUCE String class!
Definition: juce_String.h:42
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
Definition: juce_Time.cpp:218
virtual int useTimeSlice()=0
Called back by a TimeSliceThread.
Used by the TimeSliceThread class.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
Encapsulates a thread.
Definition: juce_Thread.h:46
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
Adds a client to the list.
void removeAllClients()
Removes all the active and pending clients from the list.
Holds an absolute date and time.
Definition: juce_Time.h:40
Automatically locks and unlocks a mutex object.
TimeSliceThread(const String &threadName)
Creates a TimeSliceThread.
bool wait(int timeOutMilliseconds) const
Suspends the execution of this thread until either the specified timeout period has elapsed...
Automatically unlocks and re-locks a mutex object.
void moveToFrontOfQueue(TimeSliceClient *clientToMove)
If the given client is waiting in the queue, it will be moved to the front and given a time-slice as ...