diff options
Diffstat (limited to 'gruel/src')
-rw-r--r-- | gruel/src/include/gruel/thread.h | 102 | ||||
-rw-r--r-- | gruel/src/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gruel/src/lib/thread.cc | 226 | ||||
-rw-r--r-- | gruel/src/python/CMakeLists.txt | 5 | ||||
-rw-r--r-- | gruel/src/python/pmt/__init__.py | 2 | ||||
-rw-r--r-- | gruel/src/python/pmt/pmt_to_python.py | 97 | ||||
-rwxr-xr-x | gruel/src/python/qa_pmt_to_python.py | 34 |
7 files changed, 464 insertions, 3 deletions
diff --git a/gruel/src/include/gruel/thread.h b/gruel/src/include/gruel/thread.h index c0b54b0a4..60832675c 100644 --- a/gruel/src/include/gruel/thread.h +++ b/gruel/src/include/gruel/thread.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009,2010,2011 Free Software Foundation, Inc. + * Copyright 2009-2012 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -26,6 +26,17 @@ #include <boost/thread/mutex.hpp> #include <boost/thread/locks.hpp> #include <boost/thread/condition_variable.hpp> +#include <vector> + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include <windows.h> + +#endif namespace gruel { @@ -34,6 +45,95 @@ namespace gruel { typedef boost::unique_lock<boost::mutex> scoped_lock; typedef boost::condition_variable condition_variable; + /*! \brief a system-dependent typedef for the underlying thread type. + */ +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + typedef HANDLE gr_thread_t; +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + typedef pthread_t gr_thread_t; +#else + typedef pthread_t gr_thread_t; +#endif + + /*! \brief Get the current thread's ID as a gr_thread_t + * + * We use this when setting the thread affinity or any other + * low-level thread settings. Can be called withing a GNU Radio + * block to get a reference to its current thread ID. + */ + GRUEL_API gr_thread_t get_current_thread_id(); + + /*! \brief Bind the current thread to a set of cores. + * + * Wrapper for system-dependent calls to set the affinity of the + * current thread to the processor mask. The mask is simply a + * 1-demensional vector containing the processor or core number from + * 0 to N-1 for N cores. + * + * Note: this does not work on OSX; it is a nop call since OSX does + * not support the concept of thread affinity (and what they do + * support in this way since 10.5 is not what we want or can use in + * this fashion). + */ + GRUEL_API void thread_bind_to_processor(const std::vector<unsigned int> &mask); + + /*! \brief Convineince function to bind the current thread to a single core. + * + * Wrapper for system-dependent calls to set the affinity of the + * current thread to a given core from 0 to N-1 for N cores. + * + * Note: this does not work on OSX; it is a nop call since OSX does + * not support the concept of thread affinity (and what they do + * support in this way since 10.5 is not what we want or can use in + * this fashion). + */ + GRUEL_API void thread_bind_to_processor(unsigned int n); + + /*! \brief Bind a thread to a set of cores. + * + * Wrapper for system-dependent calls to set the affinity of the + * given thread ID to the processor mask. The mask is simply a + * 1-demensional vector containing the processor or core number from + * 0 to N-1 for N cores. + * + * Note: this does not work on OSX; it is a nop call since OSX does + * not support the concept of thread affinity (and what they do + * support in this way since 10.5 is not what we want or can use in + * this fashion). + */ + GRUEL_API void thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask); + + + /*! \brief Convineince function to bind the a thread to a single core. + * + * Wrapper for system-dependent calls to set the affinity of the + * given thread ID to a given core from 0 to N-1 for N cores. + * + * Note: this does not work on OSX; it is a nop call since OSX does + * not support the concept of thread affinity (and what they do + * support in this way since 10.5 is not what we want or can use in + * this fashion). + */ + GRUEL_API void thread_bind_to_processor(gr_thread_t thread, unsigned int n); + + /*! \brief Remove any thread-processor affinity for the current thread. + * + * Note: this does not work on OSX; it is a nop call since OSX does + * not support the concept of thread affinity (and what they do + * support in this way since 10.5 is not what we want or can use in + * this fashion). + */ + GRUEL_API void thread_unbind(); + + /*! \brief Remove any thread-processor affinity for a given thread ID. + * + * Note: this does not work on OSX; it is a nop call since OSX does + * not support the concept of thread affinity (and what they do + * support in this way since 10.5 is not what we want or can use in + * this fashion). + */ + GRUEL_API void thread_unbind(gr_thread_t thread); + } /* namespace gruel */ #endif /* INCLUDED_THREAD_H */ diff --git a/gruel/src/lib/CMakeLists.txt b/gruel/src/lib/CMakeLists.txt index e33b80d64..717d56660 100644 --- a/gruel/src/lib/CMakeLists.txt +++ b/gruel/src/lib/CMakeLists.txt @@ -76,6 +76,7 @@ link_directories(${Boost_LIBRARY_DIRS}) list(APPEND gruel_sources realtime.cc sys_pri.cc + thread.cc thread_body_wrapper.cc thread_group.cc ) diff --git a/gruel/src/lib/thread.cc b/gruel/src/lib/thread.cc new file mode 100644 index 000000000..8ebe822fb --- /dev/null +++ b/gruel/src/lib/thread.cc @@ -0,0 +1,226 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gruel/thread.h> + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + +#include <Windows.h> + +namespace gruel { + + gr_thread_t + get_current_thread_id() + { + return GetCurrentThread(); + } + + void + thread_bind_to_processor(unsigned int n) + { + std::vector<unsigned int> mask(1, n); + thread_bind_to_processor(get_current_thread_id(), mask); + } + + void + thread_bind_to_processor(const std::vector<unsigned int> &mask) + { + thread_bind_to_processor(get_current_thread_id(), mask); + } + + void + thread_bind_to_processor(gr_thread_t thread, unsigned int n) + { + std::vector<unsigned int> mask(1, n); + thread_bind_to_processor(thread, mask); + } + + void + thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask) + { + //DWORD_PTR mask = (1 << n); + DWORD_PTR dword_mask = 0; + + std::vector<unsigned int> _mask = mask; + std::vector<unsigned int>::iterator itr; + for(itr = _mask.begin(); itr != _mask.end(); itr++) + dword_mask |= (1 << (*itr)); + + DWORD_PTR ret = SetThreadAffinityMask(thread, dword_mask); + if(ret == 0) { + std::stringstream s; + s << "thread_bind_to_processor failed with error: " << GetLastError() << std::endl; + throw std::runtime_error(s.str()); + } + } + + void + thread_unbind() + { + thread_unbind(get_current_thread_id()); + } + + void + thread_unbind(gr_thread_t thread) + { + DWORD_PTR dword_mask = sizeof(DWORD_PTR) - 1; + DWORD_PTR ret = SetThreadAffinityMask(thread, dword_mask); + if(ret == 0) { + std::stringstream s; + s << "thread_unbind failed with error: " << GetLastError() << std::endl; + throw std::runtime_error(s.str()); + } + } +} /* namespace gruel */ + +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) + +namespace gruel { + + gr_thread_t + get_current_thread_id() + { + // Not implemented on OSX + } + + void + thread_bind_to_processor(unsigned int n) + { + // Not implemented on OSX + } + + void + thread_bind_to_processor(gr_thread_t thread, unsigned int n) + { + // Not implemented on OSX + } + + void + thread_bind_to_processor(const std::vector<unsigned int> &mask) + { + // Not implemented on OSX + } + + void + thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask) + { + // Not implemented on OSX + } + + void + thread_unbind() + { + // Not implemented on OSX + } + + void + thread_unbind(gr_thread_t thread) + { + // Not implemented on OSX + } +} /* namespace gruel */ + +#else + +#include <sstream> +#include <stdexcept> +#include <pthread.h> + +namespace gruel { + + gr_thread_t + get_current_thread_id() + { + return pthread_self(); + } + + void + thread_bind_to_processor(unsigned int n) + { + std::vector<unsigned int> mask(1, n); + thread_bind_to_processor(get_current_thread_id(), mask); + } + + void + thread_bind_to_processor(const std::vector<unsigned int> &mask) + { + thread_bind_to_processor(get_current_thread_id(), mask); + } + + void + thread_bind_to_processor(gr_thread_t thread, unsigned int n) + { + std::vector<unsigned int> mask(1, n); + thread_bind_to_processor(thread, mask); + } + + void + thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask) + { + cpu_set_t set; + size_t len = sizeof(cpu_set_t); + std::vector<unsigned int> _mask = mask; + std::vector<unsigned int>::iterator itr; + + CPU_ZERO(&set); + for(itr = _mask.begin(); itr != _mask.end(); itr++) + CPU_SET(*itr, &set); + + int ret = pthread_setaffinity_np(thread, len, &set); + if(ret != 0) { + std::stringstream s; + s << "thread_bind_to_processor failed with error: " << ret << std::endl; + throw std::runtime_error(s.str()); + } + } + + void + thread_unbind() + { + thread_unbind(get_current_thread_id()); + } + + void + thread_unbind(gr_thread_t thread) + { + cpu_set_t set; + size_t len = sizeof(cpu_set_t); + + CPU_ZERO(&set); + long ncpus = sysconf(_SC_NPROCESSORS_ONLN); + for(long n = 0; n < ncpus; n++) { + CPU_SET(n, &set); + } + + int ret = pthread_setaffinity_np(thread, len, &set); + if(ret != 0) { + std::stringstream s; + s << "thread_unbind failed with error: " << ret << std::endl; + throw std::runtime_error(s.str()); + } + } +} /* namespace gruel */ + +#endif diff --git a/gruel/src/python/CMakeLists.txt b/gruel/src/python/CMakeLists.txt index 13f2111ba..f5c4ac47a 100644 --- a/gruel/src/python/CMakeLists.txt +++ b/gruel/src/python/CMakeLists.txt @@ -28,8 +28,9 @@ GR_PYTHON_INSTALL( COMPONENT "gruel_python" ) -GR_PYTHON_INSTALL( - FILES pmt/__init__.py +GR_PYTHON_INSTALL(FILES + pmt/__init__.py + pmt/pmt_to_python.py DESTINATION ${GR_PYTHON_DIR}/gruel/pmt COMPONENT "gruel_python" ) diff --git a/gruel/src/python/pmt/__init__.py b/gruel/src/python/pmt/__init__.py index 0862af0eb..bc933e80a 100644 --- a/gruel/src/python/pmt/__init__.py +++ b/gruel/src/python/pmt/__init__.py @@ -26,4 +26,6 @@ The GNU Radio Utility Etcetera Library's Polymorphic Types for Python. ''' from pmt_swig import * +from pmt_to_python import pmt_to_python as to_python +from pmt_to_python import python_to_pmt as to_pmt diff --git a/gruel/src/python/pmt/pmt_to_python.py b/gruel/src/python/pmt/pmt_to_python.py new file mode 100644 index 000000000..030c1c11d --- /dev/null +++ b/gruel/src/python/pmt/pmt_to_python.py @@ -0,0 +1,97 @@ +# Copyright 2012,2013 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# 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. + +try: import pmt_swig as pmt +except: import pmt +import numpy + +#define missing +def pmt_to_tuple(p): + elems = list() + for i in range(pmt.pmt_length(p)): + elem = pmt.pmt_tuple_ref(p, i) + elems.append(pmt_to_python(elem)) + return tuple(elems) + +def pmt_from_tuple(p): + args = map(python_to_pmt, p) + return pmt.pmt_make_tuple(*args) + +def pmt_to_vector(p): + v = list() + for i in range(pmt.pmt_length(p)): + elem = pmt.pmt_vector_ref(p, i) + v.append(pmt_to_python(elem)) + return v + +def pmt_from_vector(p): + v = pmt.pmt_make_vector(len(p), pmt.PMT_NIL) + for i, elem in enumerate(p): + pmt.pmt_vector_set(v, i, python_to_pmt(elem)) + return v + +def pmt_to_dict(p): + d = dict() + items = pmt.pmt_dict_items(p) + for i in range(pmt.pmt_length(items)): + pair = pmt.pmt_nth(i, items) + k = pmt.pmt_car(pair) + v = pmt.pmt_cdr(pair) + d[pmt_to_python(k)] = pmt_to_python(v) + return d + +def pmt_from_dict(p): + d = pmt.pmt_make_dict() + for k, v in p.iteritems(): + #dict is immutable -> therefore pmt_dict_add returns the new dict + d = pmt.pmt_dict_add(d, python_to_pmt(k), python_to_pmt(v)) + return d + +def numpy_to_blob(p): + p = p.view(numpy.uint8) + b = pmt.pmt_make_blob(len(p)) + pmt.pmt_blob_data(b)[:] = p + return b + +THE_TABLE = ( #python type, check pmt type, to python, from python + (None, pmt.pmt_is_null, lambda x: None, lambda x: pmt.PMT_NIL), + (bool, pmt.pmt_is_bool, pmt.pmt_to_bool, pmt.pmt_from_bool), + (str, pmt.pmt_is_symbol, pmt.pmt_symbol_to_string, pmt.pmt_string_to_symbol), + (int, pmt.pmt_is_integer, pmt.pmt_to_long, pmt.pmt_from_long), + (long, pmt.pmt_is_uint64, lambda x: long(pmt.pmt_to_uint64(x)), pmt.pmt_from_uint64), + (float, pmt.pmt_is_real, pmt.pmt_to_double, pmt.pmt_from_double), + (complex, pmt.pmt_is_complex, pmt.pmt_to_complex, pmt.pmt_from_complex), + (tuple, pmt.pmt_is_tuple, pmt_to_tuple, pmt_from_tuple), + (list, pmt.pmt_is_vector, pmt_to_vector, pmt_from_vector), + (dict, pmt.pmt_is_dict, pmt_to_dict, pmt_from_dict), + (numpy.ndarray, pmt.pmt_is_blob, pmt.pmt_blob_data, numpy_to_blob), +) + +def pmt_to_python(p): + for python_type, pmt_check, to_python, from_python in THE_TABLE: + if pmt_check(p): return to_python(p) + return p #give up, we return the same + +def python_to_pmt(p): + for python_type, pmt_check, to_python, from_python in THE_TABLE: + if python_type is None: + if p == None: return from_python(p) + elif isinstance(p, python_type): return from_python(p) + return p #give up, we return the same + diff --git a/gruel/src/python/qa_pmt_to_python.py b/gruel/src/python/qa_pmt_to_python.py new file mode 100755 index 000000000..c63403a52 --- /dev/null +++ b/gruel/src/python/qa_pmt_to_python.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# +# Copyright 2013 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# 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. +# + +import unittest +import pmt + +class test_gruel_pmt_to_python(unittest.TestCase): + + def test01 (self): + b = pmt.pmt_from_double(123765) + self.assertEqual(pmt.to_python(b), 123765) + t = pmt.to_pmt(range(5)) + +if __name__ == '__main__': + unittest.main() |