History

the only constant is change.

Ge Wang committed 9 years ago

Commit 009ac191 parent b1e2669181 files · +0 −3911Browse files

Showing the changes to src/core/util_thread.cpp (1 of 181 files). Show all

Unified · Split

src/core/util_thread.cpp+523−0
@@ -0,0 +1,523 @@
1+/*----------------------------------------------------------------------------
2+ ChucK Concurrent, On-the-fly Audio Programming Language
3+ Compiler and Virtual Machine
4+
5+ Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6+ http://chuck.stanford.edu/
7+ http://chuck.cs.princeton.edu/
8+
9+ This program is free software; you can redistribute it and/or modify
10+ it under the terms of the GNU General Public License as published by
11+ the Free Software Foundation; either version 2 of the License, or
12+ (at your option) any later version.
13+
14+ This program is distributed in the hope that it will be useful,
15+ but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ GNU General Public License for more details.
18+
19+ You should have received a copy of the GNU General Public License
20+ along with this program; if not, write to the Free Software
21+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22+ U.S.A.
23+-----------------------------------------------------------------------------*/
24+
25+//-----------------------------------------------------------------------------
26+// name: util_thread.cpp
27+// desc: thread utilities
28+//
29+// authors: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu)
30+// based on STK's Thread
31+// Perry R. Cook + Gary Scavone
32+// date: autumn 2004
33+//-----------------------------------------------------------------------------
34+#include "util_thread.h"
35+#include "util_buffers.h"
36+#include "chuck_errmsg.h"
37+#ifndef __PLATFORM_WIN32__
38+#include <unistd.h> // usleep
39+#endif
40+
41+
42+
43+
44+// static instantiation
45+const size_t XWriteThread::PRODUCER_BUFFER_SIZE = 1024;
46+XWriteThread * XWriteThread::o_defaultWriteThread = NULL;
47+
48+
49+
50+
51+
52+//-----------------------------------------------------------------------------
53+// name: XThread()
54+// desc: ...
55+//-----------------------------------------------------------------------------
56+XThread::XThread( )
57+{
58+ thread = 0;
59+}
60+
61+
62+
63+
64+//-----------------------------------------------------------------------------
65+// name: ~XThread()
66+// desc: ...
67+//-----------------------------------------------------------------------------
68+XThread::~XThread( )
69+{
70+ if( thread != 0 )
71+ {
72+#if defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__)
73+ pthread_cancel(thread);
74+ pthread_join(thread, NULL);
75+#elif defined(__PLATFORM_WIN32__)
76+ TerminateThread((HANDLE)thread, 0);
77+#endif
78+ }
79+}
80+
81+
82+
83+
84+//-----------------------------------------------------------------------------
85+// name: start()
86+// desc: ...
87+//-----------------------------------------------------------------------------
88+bool XThread::start( THREAD_FUNCTION routine, void * ptr )
89+{
90+ bool result = false;
91+
92+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
93+ if( pthread_create( &thread, NULL, *routine, ptr ) == 0 )
94+ result = true;
95+#elif defined(__PLATFORM_WIN32__)
96+ unsigned thread_id;
97+ thread = _beginthreadex( NULL, 0, routine, ptr, 0, &thread_id );
98+ if( thread ) result = true;
99+#endif
100+ return result;
101+}
102+
103+
104+
105+
106+//-----------------------------------------------------------------------------
107+// name: wait()
108+// desc: ...
109+//-----------------------------------------------------------------------------
110+bool XThread::wait( long milliseconds, bool cancel )
111+{
112+ bool result = false;
113+
114+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
115+ if(cancel) pthread_cancel(thread);
116+ pthread_join(thread, NULL);
117+#elif defined(__PLATFORM_WIN32__)
118+ DWORD timeout, retval;
119+ if( milliseconds < 0 ) timeout = INFINITE;
120+ else timeout = milliseconds;
121+ retval = WaitForSingleObject( (HANDLE)thread, timeout );
122+ if( retval == WAIT_OBJECT_0 ) {
123+ CloseHandle( (HANDLE)thread );
124+ thread = 0;
125+ result = true;
126+ }
127+#endif
128+
129+ return result;
130+}
131+
132+
133+
134+
135+//-----------------------------------------------------------------------------
136+// name: test()
137+// desc: ...
138+//-----------------------------------------------------------------------------
139+void XThread :: test( )
140+{
141+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
142+ pthread_testcancel();
143+#endif
144+}
145+
146+
147+
148+
149+//-----------------------------------------------------------------------------
150+// name: XMutex()
151+// desc: ...
152+//-----------------------------------------------------------------------------
153+XMutex::XMutex( )
154+{
155+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
156+ pthread_mutex_init(&mutex, NULL);
157+#elif defined(__PLATFORM_WIN32__)
158+ InitializeCriticalSection(&mutex);
159+#endif
160+}
161+
162+
163+
164+
165+//-----------------------------------------------------------------------------
166+// name: XMutex()
167+// desc: ...
168+//-----------------------------------------------------------------------------
169+XMutex::~XMutex( )
170+{
171+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
172+ pthread_mutex_destroy( &mutex );
173+#elif defined(__PLATFORM_WIN32__)
174+ DeleteCriticalSection(&mutex);
175+#endif
176+}
177+
178+
179+
180+
181+//-----------------------------------------------------------------------------
182+// name: acquire()
183+// desc: ...
184+//-----------------------------------------------------------------------------
185+void XMutex::acquire( )
186+{
187+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
188+ pthread_mutex_lock(&mutex);
189+#elif defined(__PLATFORM_WIN32__)
190+ EnterCriticalSection(&mutex);
191+#endif
192+}
193+
194+
195+
196+
197+//-----------------------------------------------------------------------------
198+// name: unlock()
199+// desc: ...
200+//-----------------------------------------------------------------------------
201+void XMutex::release( )
202+{
203+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
204+ pthread_mutex_unlock(&mutex);
205+#elif defined(__PLATFORM_WIN32__)
206+ LeaveCriticalSection(&mutex);
207+#endif
208+}
209+
210+
211+
212+
213+//-----------------------------------------------------------------------------
214+// name: shared()
215+// desc: get XWriteThread shared instance
216+//-----------------------------------------------------------------------------
217+XWriteThread * XWriteThread::shared()
218+{
219+ // static XWriteThread s_defaultWriteThread;
220+
221+ // check
222+ if( o_defaultWriteThread == NULL )
223+ o_defaultWriteThread = new XWriteThread();
224+
225+ return o_defaultWriteThread;
226+}
227+
228+
229+
230+
231+//-----------------------------------------------------------------------------
232+// name: XWriteThread()
233+// desc: constructor
234+//-----------------------------------------------------------------------------
235+XWriteThread::XWriteThread(size_t data_buffer_size, size_t msg_buffer_size)
236+ :
237+ m_msg_buffer(new CircularBuffer<Message>(msg_buffer_size)),
238+ m_data_buffer(new FastCircularBuffer),
239+ m_thread_buffer(new t_CKBYTE[data_buffer_size])
240+{
241+ m_data_buffer->initialize( data_buffer_size, sizeof(char) );
242+ m_thread_exit = FALSE;
243+ m_thread.start( write_cb, this );
244+ m_stream = NULL;
245+ m_bytes_in_buffer = 0;
246+}
247+
248+
249+
250+
251+//-----------------------------------------------------------------------------
252+// name: ~XWriteThread()
253+// desc: destructor
254+//-----------------------------------------------------------------------------
255+XWriteThread::~XWriteThread()
256+{
257+ SAFE_DELETE( m_msg_buffer );
258+ SAFE_DELETE( m_data_buffer );
259+ SAFE_DELETE_ARRAY( m_thread_buffer );
260+}
261+
262+
263+
264+
265+//-----------------------------------------------------------------------------
266+// name: shutdown()
267+// desc: close down writer thread and delete in background
268+//-----------------------------------------------------------------------------
269+void XWriteThread::shutdown()
270+{
271+ Message msg;
272+ msg.operation = Message::SHUTDOWN;
273+ m_msg_buffer->put( msg );
274+
275+ m_thread.wait( -1, false );
276+}
277+
278+
279+
280+
281+//-----------------------------------------------------------------------------
282+// name: fwrite()
283+// desc: ...
284+//-----------------------------------------------------------------------------
285+size_t XWriteThread::fwrite(const void * ptr, size_t size, size_t nitems, FILE * stream)
286+{
287+ if(stream != m_stream)
288+ flush_data_buffer();
289+
290+ // TODO: overflow detection
291+ if(m_data_buffer->put((char*)ptr, size*nitems) == 0)
292+ {
293+ EM_log(CK_LOG_SEVERE, "XWriteThread::fwrite: data buffer overflow");
294+ }
295+
296+ m_bytes_in_buffer += size*nitems;
297+ m_stream = stream;
298+
299+ if(m_bytes_in_buffer >= PRODUCER_BUFFER_SIZE)
300+ flush_data_buffer();
301+
302+ return nitems;
303+}
304+
305+
306+
307+
308+//-----------------------------------------------------------------------------
309+// name: fseek()
310+// desc: ...
311+//-----------------------------------------------------------------------------
312+int XWriteThread::fseek(FILE *stream, long offset, int whence)
313+{
314+ flush_data_buffer();
315+
316+ Message msg;
317+ msg.file = stream;
318+ msg.operation = Message::SEEK;
319+ msg.seek.offset = offset;
320+ msg.seek.whence = whence;
321+ m_msg_buffer->put(msg);
322+
323+ return 0;
324+}
325+
326+
327+
328+
329+//-----------------------------------------------------------------------------
330+// name: fflush()
331+// desc: ...
332+//-----------------------------------------------------------------------------
333+int XWriteThread::fflush(FILE *stream)
334+{
335+ flush_data_buffer();
336+
337+ Message msg;
338+ msg.file = stream;
339+ msg.operation = Message::FLUSH;
340+ m_msg_buffer->put(msg);
341+
342+ return 0;
343+}
344+
345+
346+
347+
348+//-----------------------------------------------------------------------------
349+// name: fclose()
350+// desc: ...
351+//-----------------------------------------------------------------------------
352+int XWriteThread::fclose(FILE *stream)
353+{
354+ flush_data_buffer();
355+
356+ Message msg;
357+ msg.file = stream;
358+ msg.operation = Message::CLOSE;
359+ m_msg_buffer->put(msg);
360+
361+ return 0;
362+}
363+
364+
365+
366+
367+//-----------------------------------------------------------------------------
368+// name: flush_data_buffer()
369+// desc: ...
370+//-----------------------------------------------------------------------------
371+void XWriteThread::flush_data_buffer()
372+{
373+ if(m_bytes_in_buffer > 0)
374+ {
375+ Message msg;
376+ msg.file = m_stream;
377+ msg.operation = Message::WRITE;
378+ msg.write.data_size = m_bytes_in_buffer;
379+ m_msg_buffer->put(msg);
380+
381+ m_bytes_in_buffer = 0;
382+ }
383+}
384+
385+
386+
387+
388+//-----------------------------------------------------------------------------
389+// name: write_cb()
390+// desc: thread function
391+//-----------------------------------------------------------------------------
392+#if ( defined(__PLATFORM_MACOSX__) || defined(__PLATFORM_LINUX__) || defined(__WINDOWS_PTHREAD__) )
393+void * XWriteThread::write_cb(void * _thiss)
394+#elif defined(__PLATFORM_WIN32__)
395+unsigned XWriteThread::write_cb(void * _thiss)
396+#endif
397+{
398+ XWriteThread * _this = (XWriteThread *) _thiss;
399+ Message msg;
400+
401+ while(!_this->m_thread_exit)
402+ {
403+ while(_this->m_msg_buffer->get(msg))
404+ {
405+ if(msg.operation == Message::WRITE)
406+ {
407+ size_t actual_size = _this->m_data_buffer->get(_this->m_thread_buffer,
408+ msg.write.data_size);
409+ if(actual_size != msg.write.data_size)
410+ {
411+ EM_log(CK_LOG_SEVERE, "XWriteThread: buffered data size mismatch (%li : %li)",
412+ msg.write.data_size, actual_size);
413+ }
414+
415+ ::fwrite(_this->m_thread_buffer, 1, actual_size, msg.file);
416+ }
417+ else if(msg.operation == Message::SEEK)
418+ {
419+ ::fseek(msg.file, msg.seek.offset, msg.seek.whence);
420+ }
421+ else if(msg.operation == Message::FLUSH)
422+ {
423+ ::fflush(msg.file);
424+ }
425+ else if(msg.operation == Message::CLOSE)
426+ {
427+ ::fclose(msg.file);
428+ }
429+ else if(msg.operation == Message::SHUTDOWN)
430+ {
431+ _this->m_thread_exit = TRUE;
432+ break;
433+ }
434+ }
435+
436+ usleep(1000);
437+ }
438+
439+ delete _this;
440+ _thiss = _this = NULL;
441+
442+ return 0;
443+}
444+
445+
446+
447+
448+#ifdef __MACOSX_CORE__
449+t_CKINT XThreadUtil::our_priority = 85;
450+#else
451+t_CKINT XThreadUtil::our_priority = 0x7fffffff;
452+#endif
453+
454+
455+
456+
457+#if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
458+//-----------------------------------------------------------------------------
459+// name: set_priority()
460+// desc: set thread priority
461+//-----------------------------------------------------------------------------
462+t_CKBOOL XThreadUtil::set_priority( CHUCK_THREAD tid, t_CKINT priority )
463+{
464+ struct sched_param param;
465+ int policy;
466+
467+ // log
468+ EM_log( CK_LOG_FINE, "setting thread priority to: %ld...", priority );
469+
470+ // get for thread
471+ if( pthread_getschedparam( tid, &policy, &param) )
472+ return FALSE;
473+
474+ // priority
475+ param.sched_priority = priority;
476+ // policy
477+ policy = SCHED_RR;
478+ // set for thread, pthread style
479+ if( pthread_setschedparam( tid, policy, &param ) )
480+ return FALSE;
481+
482+ return TRUE;
483+}
484+//-----------------------------------------------------------------------------
485+// name: set_priority()
486+// desc: set thread priority for self
487+//-----------------------------------------------------------------------------
488+t_CKBOOL XThreadUtil::set_priority( t_CKINT priority )
489+{
490+ // pass it along with self thread
491+ set_priority( pthread_self(), priority );
492+ return TRUE;
493+}
494+#else
495+//-----------------------------------------------------------------------------
496+// name: set_priority()
497+// desc: set thread priority
498+//-----------------------------------------------------------------------------
499+t_CKBOOL XThreadUtil::set_priority( CHUCK_THREAD tid, t_CKINT priority )
500+{
501+ // if priority is 0 then done
502+ if( !priority ) return TRUE;
503+
504+ // log
505+ EM_log( CK_LOG_FINE, "setting thread priority to: %ld...", priority );
506+
507+ // set the priority the thread, windows style
508+ if( !SetThreadPriority( tid, priority ) )
509+ return FALSE;
510+
511+ return TRUE;
512+}
513+//-----------------------------------------------------------------------------
514+// name: set_priority()
515+// desc: set thread priority for self
516+//-----------------------------------------------------------------------------
517+t_CKBOOL XThreadUtil::set_priority( t_CKINT priority )
518+{
519+ // pass it along with self thread
520+ set_priority( GetCurrentThread(), priority );
521+ return TRUE;
522+}
523+#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t