mirror of https://gerrit.osmocom.org/libusrp
initial move from mld_threads to gruel:: namespace threads and such
This commit is contained in:
parent
b91b8b79ae
commit
5dbc6a3bcf
|
@ -1,7 +1,7 @@
|
||||||
#
|
#
|
||||||
# USRP - Universal Software Radio Peripheral
|
# USRP - Universal Software Radio Peripheral
|
||||||
#
|
#
|
||||||
# Copyright (C) 2003,2004,2006,2007,2008,2009 Free Software Foundation, Inc.
|
# Copyright (C) 2003,2004,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -31,10 +31,10 @@ libusrp_la_common_LIBADD = \
|
||||||
$(BOOST_THREAD_LIB) \
|
$(BOOST_THREAD_LIB) \
|
||||||
../misc/libmisc.la
|
../misc/libmisc.la
|
||||||
|
|
||||||
# darwin fusb requires omnithreads
|
# darwin fusb requires gruel (for threading)
|
||||||
if FUSB_TECH_darwin
|
if FUSB_TECH_darwin
|
||||||
AM_CPPFLAGS = $(common_INCLUDES) $(OMNITHREAD_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
|
AM_CPPFLAGS = $(common_INCLUDES) $(GRUEL_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
|
||||||
libusrp_la_LIBADD = $(libusrp_la_common_LIBADD) $(OMNITHREAD_LA)
|
libusrp_la_LIBADD = $(libusrp_la_common_LIBADD) $(GRUEL_LA)
|
||||||
libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS) -framework CoreFoundation
|
libusrp_la_LDFLAGS = $(libusrp_la_common_LDFLAGS) -framework CoreFoundation
|
||||||
else
|
else
|
||||||
AM_CPPFLAGS = $(common_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
|
AM_CPPFLAGS = $(common_INCLUDES) $(BOOST_CPPFLAGS) $(WITH_INCLUDES)
|
||||||
|
@ -70,7 +70,6 @@ darwin_CODE = \
|
||||||
circular_buffer.h \
|
circular_buffer.h \
|
||||||
circular_linked_list.h \
|
circular_linked_list.h \
|
||||||
darwin_libusb.h \
|
darwin_libusb.h \
|
||||||
mld_threads.h \
|
|
||||||
usrp_prims_libusb0.cc
|
usrp_prims_libusb0.cc
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- c++ -*- */
|
/* -*- c++ -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2006,2009 Free Software Foundation, Inc.
|
* Copyright 2006,2009,2010 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GNU Radio.
|
* This file is part of GNU Radio.
|
||||||
*
|
*
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
#ifndef _CIRCULAR_BUFFER_H_
|
#ifndef _CIRCULAR_BUFFER_H_
|
||||||
#define _CIRCULAR_BUFFER_H_
|
#define _CIRCULAR_BUFFER_H_
|
||||||
|
|
||||||
#include "mld_threads.h"
|
#include <gruel/thread.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
@ -37,7 +37,8 @@
|
||||||
#define DEBUG(X) do{} while(0);
|
#define DEBUG(X) do{} while(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class T> class circular_buffer
|
template <class T>
|
||||||
|
class circular_buffer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// the buffer to use
|
// the buffer to use
|
||||||
|
@ -48,8 +49,9 @@ private:
|
||||||
size_t d_n_avail_write_I, d_n_avail_read_I;
|
size_t d_n_avail_write_I, d_n_avail_read_I;
|
||||||
|
|
||||||
// stuff to control access to class internals
|
// stuff to control access to class internals
|
||||||
mld_mutex_ptr d_internal;
|
gruel::mutex* d_internal;
|
||||||
mld_condition_ptr d_readBlock, d_writeBlock;
|
gruel::condition_variable* d_readBlock;
|
||||||
|
gruel::condition_variable* d_writeBlock;
|
||||||
|
|
||||||
// booleans to decide how to control reading, writing, and aborting
|
// booleans to decide how to control reading, writing, and aborting
|
||||||
bool d_doWriteBlock, d_doFullRead, d_doAbort;
|
bool d_doWriteBlock, d_doFullRead, d_doAbort;
|
||||||
|
@ -94,16 +96,14 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t n_avail_write_items () {
|
inline size_t n_avail_write_items () {
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
size_t retVal = d_n_avail_write_I;
|
size_t retVal = d_n_avail_write_I;
|
||||||
d_internal->unlock ();
|
|
||||||
return (retVal);
|
return (retVal);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t n_avail_read_items () {
|
inline size_t n_avail_read_items () {
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
size_t retVal = d_n_avail_read_I;
|
size_t retVal = d_n_avail_read_I;
|
||||||
d_internal->unlock ();
|
|
||||||
return (retVal);
|
return (retVal);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,13 +120,13 @@ public:
|
||||||
// create a mutex to handle contention of shared resources;
|
// create a mutex to handle contention of shared resources;
|
||||||
// any routine needed access to shared resources uses lock()
|
// any routine needed access to shared resources uses lock()
|
||||||
// before doing anything, then unlock() when finished.
|
// before doing anything, then unlock() when finished.
|
||||||
d_internal = new mld_mutex ();
|
d_internal = new gruel::mutex ();
|
||||||
// link the internal mutex to the read and write conditions;
|
// link the internal mutex to the read and write conditions;
|
||||||
// when wait() is called, the internal mutex will automatically
|
// when wait() is called, the internal mutex will automatically
|
||||||
// be unlock()'ed. Upon return (from a signal() to the condition),
|
// be unlock()'ed. Upon return (from a notify_one() to the condition),
|
||||||
// the internal mutex will be lock()'ed.
|
// the internal mutex will be lock()'ed.
|
||||||
d_readBlock = new mld_condition (d_internal);
|
d_readBlock = new gruel::condition_variable ();
|
||||||
d_writeBlock = new mld_condition (d_internal);
|
d_writeBlock = new gruel::condition_variable ();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -167,9 +167,8 @@ public:
|
||||||
if (!buf)
|
if (!buf)
|
||||||
throw std::runtime_error ("circular_buffer::enqueue(): "
|
throw std::runtime_error ("circular_buffer::enqueue(): "
|
||||||
"input buffer is NULL.\n");
|
"input buffer is NULL.\n");
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
if (d_doAbort) {
|
if (d_doAbort) {
|
||||||
d_internal->unlock ();
|
|
||||||
return (2);
|
return (2);
|
||||||
}
|
}
|
||||||
// set the return value to 1: success; change if needed
|
// set the return value to 1: success; change if needed
|
||||||
|
@ -178,11 +177,11 @@ public:
|
||||||
if (d_doWriteBlock) {
|
if (d_doWriteBlock) {
|
||||||
while (bufLen_I > d_n_avail_write_I) {
|
while (bufLen_I > d_n_avail_write_I) {
|
||||||
DEBUG (std::cerr << "enqueue: #len > #a, waiting." << std::endl);
|
DEBUG (std::cerr << "enqueue: #len > #a, waiting." << std::endl);
|
||||||
// wait will automatically unlock() the internal mutex
|
// wait; will automatically unlock() the internal mutex via
|
||||||
d_writeBlock->wait ();
|
// the scoped lock
|
||||||
// and lock() it here.
|
d_writeBlock->wait (l);
|
||||||
|
// and auto re-lock() it here.
|
||||||
if (d_doAbort) {
|
if (d_doAbort) {
|
||||||
d_internal->unlock ();
|
|
||||||
DEBUG (std::cerr << "enqueue: #len > #a, aborting." << std::endl);
|
DEBUG (std::cerr << "enqueue: #len > #a, aborting." << std::endl);
|
||||||
return (2);
|
return (2);
|
||||||
}
|
}
|
||||||
|
@ -208,8 +207,7 @@ public:
|
||||||
d_writeNdx_I += n_now_I;
|
d_writeNdx_I += n_now_I;
|
||||||
d_n_avail_read_I += bufLen_I;
|
d_n_avail_read_I += bufLen_I;
|
||||||
d_n_avail_write_I -= bufLen_I;
|
d_n_avail_write_I -= bufLen_I;
|
||||||
d_readBlock->signal ();
|
d_readBlock->notify_one ();
|
||||||
d_internal->unlock ();
|
|
||||||
return (retval);
|
return (retval);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,19 +253,18 @@ public:
|
||||||
throw std::runtime_error ("circular_buffer::dequeue()");
|
throw std::runtime_error ("circular_buffer::dequeue()");
|
||||||
}
|
}
|
||||||
|
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
if (d_doAbort) {
|
if (d_doAbort) {
|
||||||
d_internal->unlock ();
|
|
||||||
return (2);
|
return (2);
|
||||||
}
|
}
|
||||||
if (d_doFullRead) {
|
if (d_doFullRead) {
|
||||||
while (d_n_avail_read_I < l_bufLen_I) {
|
while (d_n_avail_read_I < l_bufLen_I) {
|
||||||
DEBUG (std::cerr << "dequeue: #a < #len, waiting." << std::endl);
|
DEBUG (std::cerr << "dequeue: #a < #len, waiting." << std::endl);
|
||||||
// wait will automatically unlock() the internal mutex
|
// wait; will automatically unlock() the internal mutex via
|
||||||
d_readBlock->wait ();
|
// the scoped lock
|
||||||
// and lock() it here.
|
d_readBlock->wait (l);
|
||||||
|
// and re-lock() it here.
|
||||||
if (d_doAbort) {
|
if (d_doAbort) {
|
||||||
d_internal->unlock ();
|
|
||||||
DEBUG (std::cerr << "dequeue: #a < #len, aborting." << std::endl);
|
DEBUG (std::cerr << "dequeue: #a < #len, aborting." << std::endl);
|
||||||
return (2);
|
return (2);
|
||||||
}
|
}
|
||||||
|
@ -276,11 +273,11 @@ public:
|
||||||
} else {
|
} else {
|
||||||
while (d_n_avail_read_I == 0) {
|
while (d_n_avail_read_I == 0) {
|
||||||
DEBUG (std::cerr << "dequeue: #a == 0, waiting." << std::endl);
|
DEBUG (std::cerr << "dequeue: #a == 0, waiting." << std::endl);
|
||||||
// wait will automatically unlock() the internal mutex
|
// wait; will automatically unlock() the internal mutex via
|
||||||
d_readBlock->wait ();
|
// the scoped lock
|
||||||
// and lock() it here.
|
d_readBlock->wait (l);
|
||||||
|
// and re-lock() it here.
|
||||||
if (d_doAbort) {
|
if (d_doAbort) {
|
||||||
d_internal->unlock ();
|
|
||||||
DEBUG (std::cerr << "dequeue: #a == 0, aborting." << std::endl);
|
DEBUG (std::cerr << "dequeue: #a == 0, aborting." << std::endl);
|
||||||
return (2);
|
return (2);
|
||||||
}
|
}
|
||||||
|
@ -303,17 +300,15 @@ public:
|
||||||
*bufLen_I = l_bufLen_I;
|
*bufLen_I = l_bufLen_I;
|
||||||
d_n_avail_read_I -= l_bufLen_I;
|
d_n_avail_read_I -= l_bufLen_I;
|
||||||
d_n_avail_write_I += l_bufLen_I;
|
d_n_avail_write_I += l_bufLen_I;
|
||||||
d_writeBlock->signal ();
|
d_writeBlock->notify_one ();
|
||||||
d_internal->unlock ();
|
|
||||||
return (1);
|
return (1);
|
||||||
};
|
};
|
||||||
|
|
||||||
void abort () {
|
void abort () {
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
d_doAbort = true;
|
d_doAbort = true;
|
||||||
d_writeBlock->signal ();
|
d_writeBlock->notify_one ();
|
||||||
d_readBlock->signal ();
|
d_readBlock->notify_one ();
|
||||||
d_internal->unlock ();
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- c++ -*- */
|
/* -*- c++ -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2006,2009 Free Software Foundation, Inc.
|
* Copyright 2006,2009,2010 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GNU Radio.
|
* This file is part of GNU Radio.
|
||||||
*
|
*
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
#ifndef _CIRCULAR_LINKED_LIST_H_
|
#ifndef _CIRCULAR_LINKED_LIST_H_
|
||||||
#define _CIRCULAR_LINKED_LIST_H_
|
#define _CIRCULAR_LINKED_LIST_H_
|
||||||
|
|
||||||
#include <mld_threads.h>
|
#include <gruel/thread.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#define __INLINE__ inline
|
#define __INLINE__ inline
|
||||||
|
@ -110,8 +110,8 @@ template <class T> class circular_linked_list {
|
||||||
private:
|
private:
|
||||||
s_node_ptr d_current, d_iterate, d_available, d_inUse;
|
s_node_ptr d_current, d_iterate, d_available, d_inUse;
|
||||||
size_t d_n_nodes, d_n_used;
|
size_t d_n_nodes, d_n_used;
|
||||||
mld_mutex_ptr d_internal;
|
gruel::mutex* d_internal;
|
||||||
mld_condition_ptr d_ioBlock;
|
gruel::condition_variable* d_ioBlock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
circular_linked_list (size_t n_nodes) {
|
circular_linked_list (size_t n_nodes) {
|
||||||
|
@ -150,8 +150,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d_available = d_current = l_prev;
|
d_available = d_current = l_prev;
|
||||||
d_ioBlock = new mld_condition ();
|
d_ioBlock = new gruel::condition_variable ();
|
||||||
d_internal = d_ioBlock->mutex ();
|
d_internal = new gruel::mutex ();
|
||||||
};
|
};
|
||||||
|
|
||||||
~circular_linked_list () {
|
~circular_linked_list () {
|
||||||
|
@ -163,19 +163,21 @@ public:
|
||||||
}
|
}
|
||||||
delete d_ioBlock;
|
delete d_ioBlock;
|
||||||
d_ioBlock = NULL;
|
d_ioBlock = NULL;
|
||||||
|
delete d_internal;
|
||||||
|
d_internal = NULL;
|
||||||
d_available = d_inUse = d_iterate = d_current = NULL;
|
d_available = d_inUse = d_iterate = d_current = NULL;
|
||||||
d_n_used = d_n_nodes = 0;
|
d_n_used = d_n_nodes = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
s_node_ptr find_next_available_node () {
|
s_node_ptr find_next_available_node () {
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
// find an available node
|
// find an available node
|
||||||
s_node_ptr l_node = d_available;
|
s_node_ptr l_node = d_available;
|
||||||
DEBUG (std::cerr << "w ");
|
DEBUG (std::cerr << "w ");
|
||||||
while (! l_node) {
|
while (! l_node) {
|
||||||
DEBUG (std::cerr << "x" << std::endl);
|
DEBUG (std::cerr << "x" << std::endl);
|
||||||
// the ioBlock condition will automatically unlock() d_internal
|
// the ioBlock condition will automatically unlock() d_internal
|
||||||
d_ioBlock->wait ();
|
d_ioBlock->wait (l);
|
||||||
// and lock() is here
|
// and lock() is here
|
||||||
DEBUG (std::cerr << "y" << std::endl);
|
DEBUG (std::cerr << "y" << std::endl);
|
||||||
l_node = d_available;
|
l_node = d_available;
|
||||||
|
@ -196,13 +198,12 @@ public:
|
||||||
l_node->insert_before (d_inUse);
|
l_node->insert_before (d_inUse);
|
||||||
d_n_used++;
|
d_n_used++;
|
||||||
l_node->set_not_available ();
|
l_node->set_not_available ();
|
||||||
d_internal->unlock ();
|
|
||||||
return (l_node);
|
return (l_node);
|
||||||
};
|
};
|
||||||
|
|
||||||
void make_node_available (s_node_ptr l_node) {
|
void make_node_available (s_node_ptr l_node) {
|
||||||
if (!l_node) return;
|
if (!l_node) return;
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
DEBUG (std::cerr << "::m_n_a: #u = " << num_used()
|
DEBUG (std::cerr << "::m_n_a: #u = " << num_used()
|
||||||
<< ", node = " << l_node << std::endl);
|
<< ", node = " << l_node << std::endl);
|
||||||
// remove this node from the inUse list
|
// remove this node from the inUse list
|
||||||
|
@ -221,11 +222,8 @@ public:
|
||||||
|
|
||||||
DEBUG (std::cerr << "s" << d_n_used);
|
DEBUG (std::cerr << "s" << d_n_used);
|
||||||
// signal the condition when new data arrives
|
// signal the condition when new data arrives
|
||||||
d_ioBlock->signal ();
|
d_ioBlock->notify_one ();
|
||||||
DEBUG (std::cerr << "t ");
|
DEBUG (std::cerr << "t ");
|
||||||
|
|
||||||
// unlock the mutex for thread safety
|
|
||||||
d_internal->unlock ();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
__INLINE__ void iterate_start () { d_iterate = d_current; };
|
__INLINE__ void iterate_start () { d_iterate = d_current; };
|
||||||
|
@ -233,7 +231,7 @@ public:
|
||||||
s_node_ptr iterate_next () {
|
s_node_ptr iterate_next () {
|
||||||
#if 0
|
#if 0
|
||||||
// lock the mutex for thread safety
|
// lock the mutex for thread safety
|
||||||
d_internal->lock ();
|
gruel::scoped_lock l (*d_internal);
|
||||||
#endif
|
#endif
|
||||||
s_node_ptr l_this = NULL;
|
s_node_ptr l_this = NULL;
|
||||||
if (d_iterate) {
|
if (d_iterate) {
|
||||||
|
@ -242,10 +240,6 @@ public:
|
||||||
if (d_iterate == d_current)
|
if (d_iterate == d_current)
|
||||||
d_iterate = NULL;
|
d_iterate = NULL;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
// unlock the mutex for thread safety
|
|
||||||
d_internal->unlock ();
|
|
||||||
#endif
|
|
||||||
return (l_this);
|
return (l_this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -261,7 +255,7 @@ public:
|
||||||
__INLINE__ void num_used_dec (void) {
|
__INLINE__ void num_used_dec (void) {
|
||||||
if (d_n_used != 0) --d_n_used;
|
if (d_n_used != 0) --d_n_used;
|
||||||
// signal the condition that new data has arrived
|
// signal the condition that new data has arrived
|
||||||
d_ioBlock->signal ();
|
d_ioBlock->notify_one ();
|
||||||
};
|
};
|
||||||
__INLINE__ bool in_use () { return (d_n_used != 0); };
|
__INLINE__ bool in_use () { return (d_n_used != 0); };
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- c++ -*- */
|
/* -*- c++ -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2006,2009 Free Software Foundation, Inc.
|
* Copyright 2006,2009,2010 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GNU Radio.
|
* This file is part of GNU Radio.
|
||||||
*
|
*
|
||||||
|
@ -24,9 +24,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// tell mld_threads to NOT use omni_threads,
|
|
||||||
// but rather Darwin's pthreads
|
|
||||||
#define _USE_OMNI_THREADS_
|
|
||||||
#define DO_DEBUG 0
|
#define DO_DEBUG 0
|
||||||
|
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
|
@ -85,10 +82,12 @@ fusb_ephandle_darwin::fusb_ephandle_darwin (fusb_devhandle_darwin* dh,
|
||||||
l_buf = NULL;
|
l_buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
d_readRunning = new mld_mutex ();
|
d_readRunning = new gruel::mutex ();
|
||||||
d_runThreadRunning = new mld_mutex ();
|
d_runThreadRunning = new gruel::mutex ();
|
||||||
d_runBlock = new mld_condition ();
|
d_runBlock = new gruel::condition_variable ();
|
||||||
d_readBlock = new mld_condition ();
|
d_readBlock = new gruel::condition_variable ();
|
||||||
|
d_runBlock_mutex = new gruel::mutex ();
|
||||||
|
d_readBlock_mutex = new gruel::mutex ();
|
||||||
}
|
}
|
||||||
|
|
||||||
fusb_ephandle_darwin::~fusb_ephandle_darwin ()
|
fusb_ephandle_darwin::~fusb_ephandle_darwin ()
|
||||||
|
@ -116,6 +115,10 @@ fusb_ephandle_darwin::~fusb_ephandle_darwin ()
|
||||||
d_readRunning = NULL;
|
d_readRunning = NULL;
|
||||||
delete d_runThreadRunning;
|
delete d_runThreadRunning;
|
||||||
d_runThreadRunning = NULL;
|
d_runThreadRunning = NULL;
|
||||||
|
delete d_runBlock_mutex;
|
||||||
|
d_runBlock_mutex = NULL;
|
||||||
|
delete d_readBlock_mutex;
|
||||||
|
d_readBlock_mutex = NULL;
|
||||||
delete d_runBlock;
|
delete d_runBlock;
|
||||||
d_runBlock = NULL;
|
d_runBlock = NULL;
|
||||||
delete d_readBlock;
|
delete d_readBlock;
|
||||||
|
@ -200,14 +203,14 @@ fusb_ephandle_darwin::start ()
|
||||||
|
|
||||||
// lock the runBlock mutex, before creating the run thread.
|
// lock the runBlock mutex, before creating the run thread.
|
||||||
// this guarantees that we can control execution between these 2 threads
|
// this guarantees that we can control execution between these 2 threads
|
||||||
d_runBlock->mutex ()->lock ();
|
gruel::scoped_lock l (*d_runBlock_mutex);
|
||||||
|
|
||||||
// create the run thread, which allows OSX to process I/O separately
|
// create the run thread, which allows OSX to process I/O separately
|
||||||
d_runThread = new mld_thread (run_thread, this);
|
d_runThread = new gruel::thread (run_thread, this);
|
||||||
|
|
||||||
// wait until the run thread (and possibky read thread) are -really-
|
// wait until the run thread (and possibky read thread) are -really-
|
||||||
// going; this will unlock the mutex before waiting for a signal ()
|
// going; this will unlock the mutex before waiting for a signal ()
|
||||||
d_runBlock->wait ();
|
d_runBlock->wait (l);
|
||||||
|
|
||||||
if (usb_debug) {
|
if (usb_debug) {
|
||||||
std::cerr << "fusb_ephandle_darwin::start: " << (d_input_p ? "read" : "write")
|
std::cerr << "fusb_ephandle_darwin::start: " << (d_input_p ? "read" : "write")
|
||||||
|
@ -225,12 +228,12 @@ fusb_ephandle_darwin::run_thread (void* arg)
|
||||||
// lock the run thread running mutex; if ::stop() is called, it will
|
// lock the run thread running mutex; if ::stop() is called, it will
|
||||||
// first abort() the pipe then wait for the run thread to finish,
|
// first abort() the pipe then wait for the run thread to finish,
|
||||||
// via a lock() on this mutex
|
// via a lock() on this mutex
|
||||||
mld_mutex_ptr l_runThreadRunning = This->d_runThreadRunning;
|
gruel::mutex* l_runThreadRunning = This->d_runThreadRunning;
|
||||||
l_runThreadRunning->lock ();
|
gruel::scoped_lock l0 (*l_runThreadRunning);
|
||||||
|
|
||||||
mld_mutex_ptr l_readRunning = This->d_readRunning;
|
gruel::mutex* l_readRunning = This->d_readRunning;
|
||||||
mld_condition_ptr l_readBlock = This->d_readBlock;
|
gruel::condition_variable* l_readBlock = This->d_readBlock;
|
||||||
mld_mutex_ptr l_readBlock_mutex = l_readBlock->mutex ();
|
gruel::mutex* l_readBlock_mutex = This->d_readBlock_mutex;
|
||||||
|
|
||||||
bool l_input_p = This->d_input_p;
|
bool l_input_p = This->d_input_p;
|
||||||
|
|
||||||
|
@ -250,41 +253,39 @@ fusb_ephandle_darwin::run_thread (void* arg)
|
||||||
// get run loop reference, to allow other threads to stop
|
// get run loop reference, to allow other threads to stop
|
||||||
This->d_CFRunLoopRef = CFRunLoopGetCurrent ();
|
This->d_CFRunLoopRef = CFRunLoopGetCurrent ();
|
||||||
|
|
||||||
mld_thread_ptr l_rwThread = NULL;
|
gruel::thread* l_rwThread = NULL;
|
||||||
|
|
||||||
if (l_input_p) {
|
if (l_input_p) {
|
||||||
// lock the readBlock mutex, before creating the read thread.
|
// lock the readBlock mutex, before creating the read thread.
|
||||||
// this guarantees that we can control execution between these 2 threads
|
// this guarantees that we can control execution between these 2 threads
|
||||||
l_readBlock_mutex->lock ();
|
gruel::scoped_lock l1 (*l_readBlock_mutex);
|
||||||
// create the read thread, which just issues all of the starting
|
// create the read thread, which just issues all of the starting
|
||||||
// async read commands, then returns
|
// async read commands, then returns
|
||||||
l_rwThread = new mld_thread (read_thread, arg);
|
l_rwThread = new gruel::thread (read_thread, arg);
|
||||||
// wait until the the read thread is -really- going; this will
|
// wait until the the read thread is -really- going; this will
|
||||||
// unlock the read block mutex before waiting for a signal ()
|
// unlock the read block mutex before waiting for a signal ()
|
||||||
l_readBlock->wait ();
|
l_readBlock->wait (l1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now signal the run condition to release and finish ::start().
|
{
|
||||||
|
// now signal the run condition to release and finish ::start().
|
||||||
|
|
||||||
// lock the runBlock mutex first; this will force waiting until the
|
// lock the runBlock mutex first; this will force waiting until the
|
||||||
// ->wait() command is issued in ::start()
|
// ->wait() command is issued in ::start()
|
||||||
mld_mutex_ptr l_run_block_mutex = This->d_runBlock->mutex ();
|
gruel::mutex* l_run_block_mutex = This->d_runBlock_mutex;
|
||||||
l_run_block_mutex->lock ();
|
gruel::scoped_lock l2 (*l_run_block_mutex);
|
||||||
|
|
||||||
// now that the lock is in place, signal the parent thread that
|
// now that the lock is in place, signal the parent thread that
|
||||||
// things are running
|
// things are running
|
||||||
This->d_runBlock->signal ();
|
This->d_runBlock->notify_one ();
|
||||||
|
}
|
||||||
// release the run_block mutex, just in case
|
|
||||||
l_run_block_mutex->unlock ();
|
|
||||||
|
|
||||||
// run the loop
|
// run the loop
|
||||||
CFRunLoopRun ();
|
CFRunLoopRun ();
|
||||||
|
|
||||||
if (l_input_p) {
|
if (l_input_p) {
|
||||||
// wait for read_thread () to finish, if needed
|
// wait for read_thread () to finish, if needed
|
||||||
l_readRunning->lock ();
|
gruel::scoped_lock l3 (*l_readRunning);
|
||||||
l_readRunning->unlock ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove run loop stuff
|
// remove run loop stuff
|
||||||
|
@ -295,9 +296,6 @@ fusb_ephandle_darwin::run_thread (void* arg)
|
||||||
std::cerr << "fusb_ephandle_darwin::run_thread: finished for "
|
std::cerr << "fusb_ephandle_darwin::run_thread: finished for "
|
||||||
<< (l_input_p ? "read" : "write") << "." << std::endl;
|
<< (l_input_p ? "read" : "write") << "." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the run thread running mutex
|
|
||||||
l_runThreadRunning->unlock ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -311,23 +309,23 @@ fusb_ephandle_darwin::read_thread (void* arg)
|
||||||
|
|
||||||
// before doing anything else, lock the read running mutex. this
|
// before doing anything else, lock the read running mutex. this
|
||||||
// mutex does flow control between this thread and the run_thread
|
// mutex does flow control between this thread and the run_thread
|
||||||
mld_mutex_ptr l_readRunning = This->d_readRunning;
|
gruel::mutex* l_readRunning = This->d_readRunning;
|
||||||
l_readRunning->lock ();
|
gruel::scoped_lock l0 (*l_readRunning);
|
||||||
|
|
||||||
// signal the read condition from run_thread() to continue
|
// signal the read condition from run_thread() to continue
|
||||||
|
|
||||||
// lock the readBlock mutex first; this will force waiting until the
|
// lock the readBlock mutex first; this will force waiting until the
|
||||||
// ->wait() command is issued in ::run_thread()
|
// ->wait() command is issued in ::run_thread()
|
||||||
mld_condition_ptr l_readBlock = This->d_readBlock;
|
gruel::condition_variable* l_readBlock = This->d_readBlock;
|
||||||
mld_mutex_ptr l_read_block_mutex = l_readBlock->mutex ();
|
gruel::mutex* l_read_block_mutex = This->d_readBlock_mutex;
|
||||||
l_read_block_mutex->lock ();
|
|
||||||
|
|
||||||
// now that the lock is in place, signal the parent thread that
|
{
|
||||||
// things are running here
|
gruel::scoped_lock l1 (*l_read_block_mutex);
|
||||||
l_readBlock->signal ();
|
|
||||||
|
|
||||||
// release the run_block mutex, just in case
|
// now that the lock is in place, signal the parent thread that
|
||||||
l_read_block_mutex->unlock ();
|
// things are running here
|
||||||
|
l_readBlock->notify_one ();
|
||||||
|
}
|
||||||
|
|
||||||
// queue up all of the available read requests
|
// queue up all of the available read requests
|
||||||
s_queue_ptr l_queue = This->d_queue;
|
s_queue_ptr l_queue = This->d_queue;
|
||||||
|
@ -341,10 +339,6 @@ fusb_ephandle_darwin::read_thread (void* arg)
|
||||||
if (usb_debug) {
|
if (usb_debug) {
|
||||||
std::cerr << "fusb_ephandle_darwin::read_thread: finished." << std::endl;
|
std::cerr << "fusb_ephandle_darwin::read_thread: finished." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// release the read running mutex, to let the parent thread knows
|
|
||||||
// that this thread is finished
|
|
||||||
l_readRunning->unlock ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -569,8 +563,7 @@ fusb_ephandle_darwin::stop ()
|
||||||
CFRunLoopStop (d_CFRunLoopRef);
|
CFRunLoopStop (d_CFRunLoopRef);
|
||||||
|
|
||||||
// wait for the runThread to stop
|
// wait for the runThread to stop
|
||||||
d_runThreadRunning->lock ();
|
gruel::scoped_lock l (*d_runThreadRunning);
|
||||||
d_runThreadRunning->unlock ();
|
|
||||||
|
|
||||||
if (usb_debug) {
|
if (usb_debug) {
|
||||||
std::cerr << "fusb_ephandle_darwin::stop: " << (d_input_p ? "read" : "write")
|
std::cerr << "fusb_ephandle_darwin::stop: " << (d_input_p ? "read" : "write")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* -*- c++ -*- */
|
/* -*- c++ -*- */
|
||||||
/*
|
/*
|
||||||
* Copyright 2006,2009 Free Software Foundation, Inc.
|
* Copyright 2006,2009,2010 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GNU Radio.
|
* This file is part of GNU Radio.
|
||||||
*
|
*
|
||||||
|
@ -150,8 +150,8 @@ class fusb_ephandle_darwin : public fusb_ephandle
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
fusb_devhandle_darwin* d_devhandle;
|
fusb_devhandle_darwin* d_devhandle;
|
||||||
mld_thread_ptr d_runThread;
|
gruel::thread* d_runThread;
|
||||||
mld_mutex_ptr d_runThreadRunning;
|
gruel::mutex* d_runThreadRunning;
|
||||||
|
|
||||||
CFRunLoopRef d_CFRunLoopRef;
|
CFRunLoopRef d_CFRunLoopRef;
|
||||||
|
|
||||||
|
@ -174,8 +174,11 @@ public:
|
||||||
s_queue_ptr d_queue;
|
s_queue_ptr d_queue;
|
||||||
circular_buffer<char>* d_buffer;
|
circular_buffer<char>* d_buffer;
|
||||||
size_t d_bufLenBytes;
|
size_t d_bufLenBytes;
|
||||||
mld_mutex_ptr d_readRunning;
|
gruel::mutex* d_readRunning;
|
||||||
mld_condition_ptr d_runBlock, d_readBlock;
|
gruel::mutex* d_runBlock_mutex;
|
||||||
|
gruel::mutex* d_readBlock_mutex;
|
||||||
|
gruel::condition_variable* d_runBlock;
|
||||||
|
gruel::condition_variable* d_readBlock;
|
||||||
|
|
||||||
// CREATORS
|
// CREATORS
|
||||||
|
|
||||||
|
|
|
@ -1,275 +0,0 @@
|
||||||
/* -*- c++ -*- */
|
|
||||||
/*
|
|
||||||
* Copyright 2006 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* This file is part of GNU Radio.
|
|
||||||
*
|
|
||||||
* Primary Author: Michael Dickens, NCIP Lab, University of Notre Dame
|
|
||||||
*
|
|
||||||
* GNU Radio is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* GNU Radio is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with GNU Radio; see the file COPYING. If not, write to
|
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
||||||
* Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDED_MLD_THREADS_H_
|
|
||||||
#define _INCLUDED_MLD_THREADS_H_
|
|
||||||
|
|
||||||
/* classes which allow for either pthreads or omni_threads */
|
|
||||||
|
|
||||||
#define __macos__
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
#include <gnuradio/omnithread.h>
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#define __INLINE__ inline
|
|
||||||
|
|
||||||
#ifndef DO_DEBUG
|
|
||||||
#define DO_DEBUG 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DO_DEBUG
|
|
||||||
#define DEBUG(X) do{X} while(0);
|
|
||||||
#else
|
|
||||||
#define DEBUG(X) do{} while(0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class mld_condition_t;
|
|
||||||
|
|
||||||
class mld_mutex_t {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
typedef omni_mutex l_mutex, *l_mutex_ptr;
|
|
||||||
#else
|
|
||||||
typedef pthread_mutex_t l_mutex, *l_mutex_ptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
friend class mld_condition_t;
|
|
||||||
|
|
||||||
private:
|
|
||||||
l_mutex_ptr d_mutex;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
inline l_mutex_ptr mutex () { return (d_mutex); };
|
|
||||||
|
|
||||||
public:
|
|
||||||
__INLINE__ mld_mutex_t () {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_mutex = new omni_mutex ();
|
|
||||||
#else
|
|
||||||
d_mutex = (l_mutex_ptr) new l_mutex;
|
|
||||||
int l_ret = pthread_mutex_init (d_mutex, NULL);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "Error %d creating mutex.\n", l_ret);
|
|
||||||
throw std::runtime_error ("mld_mutex_t::mld_mutex_t()\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ ~mld_mutex_t () {
|
|
||||||
unlock ();
|
|
||||||
#ifndef _USE_OMNI_THREADS_
|
|
||||||
int l_ret = pthread_mutex_destroy (d_mutex);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "mld_mutex_t::~mld_mutex_t(): "
|
|
||||||
"Error %d destroying mutex.\n", l_ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
delete d_mutex;
|
|
||||||
d_mutex = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ void lock () {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_mutex->lock ();
|
|
||||||
#else
|
|
||||||
int l_ret = pthread_mutex_lock (d_mutex);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "mld_mutex_t::lock(): "
|
|
||||||
"Error %d locking mutex.\n", l_ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ void unlock () {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_mutex->unlock ();
|
|
||||||
#else
|
|
||||||
int l_ret = pthread_mutex_unlock (d_mutex);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "mld_mutex_t::unlock(): "
|
|
||||||
"Error %d locking mutex.\n", l_ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ bool trylock () {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
int l_ret = d_mutex->trylock ();
|
|
||||||
#else
|
|
||||||
int l_ret = pthread_mutex_unlock (d_mutex);
|
|
||||||
#endif
|
|
||||||
return (l_ret == 0 ? true : false);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void acquire () { lock(); };
|
|
||||||
inline void release () { unlock(); };
|
|
||||||
inline void wait () { lock(); };
|
|
||||||
inline void post () { unlock(); };
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef mld_mutex_t mld_mutex, *mld_mutex_ptr;
|
|
||||||
|
|
||||||
class mld_condition_t {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
typedef omni_condition l_condition, *l_condition_ptr;
|
|
||||||
#else
|
|
||||||
typedef pthread_cond_t l_condition, *l_condition_ptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
l_condition_ptr d_condition;
|
|
||||||
mld_mutex_ptr d_mutex;
|
|
||||||
bool d_i_own_mutex;
|
|
||||||
|
|
||||||
public:
|
|
||||||
__INLINE__ mld_condition_t (mld_mutex_ptr mutex = NULL) {
|
|
||||||
if (mutex) {
|
|
||||||
d_i_own_mutex = false;
|
|
||||||
d_mutex = mutex;
|
|
||||||
} else {
|
|
||||||
d_i_own_mutex = true;
|
|
||||||
d_mutex = new mld_mutex ();
|
|
||||||
}
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_condition = new omni_condition (d_mutex->mutex ());
|
|
||||||
#else
|
|
||||||
d_condition = (l_condition_ptr) new l_condition;
|
|
||||||
int l_ret = pthread_cond_init (d_condition, NULL);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "Error %d creating condition.\n", l_ret);
|
|
||||||
throw std::runtime_error ("mld_condition_t::mld_condition_t()\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ ~mld_condition_t () {
|
|
||||||
signal ();
|
|
||||||
#ifndef _USE_OMNI_THREADS_
|
|
||||||
int l_ret = pthread_cond_destroy (d_condition);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "mld_condition_t::mld_condition_t(): "
|
|
||||||
"Error %d destroying condition.\n", l_ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
delete d_condition;
|
|
||||||
d_condition = NULL;
|
|
||||||
if (d_i_own_mutex)
|
|
||||||
delete d_mutex;
|
|
||||||
d_mutex = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ mld_mutex_ptr mutex () {return (d_mutex);};
|
|
||||||
|
|
||||||
__INLINE__ void signal () {
|
|
||||||
DEBUG (fprintf (stderr, "a "););
|
|
||||||
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_condition->signal ();
|
|
||||||
#else
|
|
||||||
int l_ret = pthread_cond_signal (d_condition);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "mld_condition_t::signal(): "
|
|
||||||
"Error %d.\n", l_ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
DEBUG (fprintf (stderr, "b "););
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ void wait () {
|
|
||||||
DEBUG (fprintf (stderr, "c "););
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_condition->wait ();
|
|
||||||
#else
|
|
||||||
int l_ret = pthread_cond_wait (d_condition, d_mutex->mutex ());
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "mld_condition_t::wait(): "
|
|
||||||
"Error %d.\n", l_ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
DEBUG (fprintf (stderr, "d "););
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef mld_condition_t mld_condition, *mld_condition_ptr;
|
|
||||||
|
|
||||||
class mld_thread_t {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
typedef omni_thread l_thread, *l_thread_ptr;
|
|
||||||
#else
|
|
||||||
typedef pthread_t l_thread, *l_thread_ptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
#ifndef _USE_OMNI_THREADS_
|
|
||||||
l_thread d_thread;
|
|
||||||
void (*d_start_routine)(void*);
|
|
||||||
void *d_arg;
|
|
||||||
#else
|
|
||||||
l_thread_ptr d_thread;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _USE_OMNI_THREADS_
|
|
||||||
static void* local_start_routine (void *arg) {
|
|
||||||
mld_thread_t* This = (mld_thread_t*) arg;
|
|
||||||
(*(This->d_start_routine))(This->d_arg);
|
|
||||||
return (NULL);
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
__INLINE__ mld_thread_t (void (*start_routine)(void *), void *arg) {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
d_thread = new omni_thread (start_routine, arg);
|
|
||||||
d_thread->start ();
|
|
||||||
#else
|
|
||||||
d_start_routine = start_routine;
|
|
||||||
d_arg = arg;
|
|
||||||
int l_ret = pthread_create (&d_thread, NULL, local_start_routine, this);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "Error %d creating thread.\n", l_ret);
|
|
||||||
throw std::runtime_error ("mld_thread_t::mld_thread_t()\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
__INLINE__ ~mld_thread_t () {
|
|
||||||
#ifdef _USE_OMNI_THREADS_
|
|
||||||
// delete d_thread;
|
|
||||||
d_thread = NULL;
|
|
||||||
#else
|
|
||||||
int l_ret = pthread_detach (d_thread);
|
|
||||||
if (l_ret != 0) {
|
|
||||||
fprintf (stderr, "Error %d detaching thread.\n", l_ret);
|
|
||||||
throw std::runtime_error ("mld_thread_t::~mld_thread_t()\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef mld_thread_t mld_thread, *mld_thread_ptr;
|
|
||||||
|
|
||||||
#endif /* _INCLUDED_MLD_THREADS_H_ */
|
|
Loading…
Reference in New Issue