From 5c90e561b4519d08a90d5bfb8a7ec035ec25d337 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Tue, 29 Aug 2006 17:42:13 +0200 Subject: [PATCH] import from yans --- src/common/buffer.cc | 595 ++++++++++++++++++++++ src/common/buffer.h | 690 ++++++++++++++++++++++++++ src/common/callback-logger.h | 84 ++++ src/common/chunk-constant-data.cc | 63 +++ src/common/chunk-constant-data.h | 47 ++ src/common/chunk-llc-snap.cc | 94 ++++ src/common/chunk-llc-snap.h | 55 ++ src/common/chunk-utils.cc | 49 ++ src/common/chunk-utils.h | 38 ++ src/common/chunk.cc | 65 +++ src/common/chunk.h | 89 ++++ src/common/count-ptr-holder.tcc | 70 +++ src/common/data-writer.cc | 119 +++++ src/common/data-writer.h | 44 ++ src/common/f-traced-variable.tcc | 58 +++ src/common/ipv4-address.cc | 203 ++++++++ src/common/ipv4-address.h | 107 ++++ src/common/ipv4-network-interface.cc | 82 +++ src/common/ipv4-network-interface.h | 59 +++ src/common/llc-snap-encapsulation.cc | 89 ++++ src/common/llc-snap-encapsulation.h | 52 ++ src/common/mac-address-factory.cc | 46 ++ src/common/mac-address-factory.h | 40 ++ src/common/mac-address.cc | 187 +++++++ src/common/mac-address.h | 72 +++ src/common/mac-network-interface.cc | 96 ++++ src/common/mac-network-interface.h | 68 +++ src/common/packet-logger.cc | 42 ++ src/common/packet-logger.h | 53 ++ src/common/packet.cc | 127 +++++ src/common/packet.h | 90 ++++ src/common/pcap-writer.cc | 99 ++++ src/common/pcap-writer.h | 73 +++ src/common/population-analysis.cc | 94 ++++ src/common/population-analysis.h | 55 ++ src/common/position.cc | 47 ++ src/common/position.h | 38 ++ src/common/random-uniform-mrg32k3a.cc | 137 +++++ src/common/random-uniform.h | 57 +++ src/common/ref-ptr.h | 139 ++++++ src/common/rng-mrg32k3a.cc | 336 +++++++++++++ src/common/rng-mrg32k3a.h | 65 +++ src/common/seed-generator-mrg32k3a.cc | 61 +++ src/common/seed-generator.h | 40 ++ src/common/sgi-hashmap.h | 32 ++ src/common/si-traced-variable.tcc | 237 +++++++++ src/common/static-position.cc | 46 ++ src/common/static-position.h | 43 ++ src/common/static-speed-position.cc | 68 +++ src/common/static-speed-position.h | 51 ++ src/common/tags.cc | 322 ++++++++++++ src/common/tags.h | 292 +++++++++++ src/common/timeout.cc | 77 +++ src/common/timeout.h | 52 ++ src/common/trace-container.cc | 197 ++++++++ src/common/trace-container.h | 299 +++++++++++ src/common/trace-stream-test.cc | 68 +++ src/common/trace-stream.h | 73 +++ src/common/traced-variable-test.cc | 252 ++++++++++ src/common/ui-traced-variable.tcc | 239 +++++++++ src/common/utils.cc | 293 +++++++++++ src/common/utils.h | 43 ++ src/core/callback-test.cc | 197 ++++++++ src/core/callback.h | 518 +++++++++++++++++++ src/core/exec-commands.h | 58 +++ src/core/reference-list-test.cc | 120 +++++ src/core/reference-list.h | 117 +++++ src/core/system-file.h | 44 ++ src/core/system-mutex.h | 42 ++ src/core/system-semaphore.h | 44 ++ src/core/system-thread.h | 41 ++ src/core/test.cc | 107 ++++ src/core/test.h | 75 +++ src/core/unix-exec-commands.cc | 516 +++++++++++++++++++ src/core/unix-system-file.cc | 119 +++++ src/core/unix-system-mutex.cc | 82 +++ src/core/unix-system-semaphore.cc | 114 +++++ src/core/unix-system-thread.cc | 69 +++ src/core/unix-wall-clock-ms.cc | 74 +++ src/core/wall-clock-ms.h | 40 ++ src/core/win32-system-file.cc | 86 ++++ src/core/win32-system-mutex.cc | 78 +++ src/core/win32-system-semaphore.cc | 103 ++++ src/core/win32-system-thread.cc | 66 +++ src/core/win32-wall-clock-ms.cc | 65 +++ src/simulator/event-impl.cc | 67 +++ src/simulator/event-impl.h | 49 ++ src/simulator/event-tcc-test.cc | 110 ++++ src/simulator/event-tcc.cc | 47 ++ src/simulator/event.h | 140 ++++++ src/simulator/event.tcc | 454 +++++++++++++++++ src/simulator/scheduler-heap.cc | 243 +++++++++ src/simulator/scheduler-heap.h | 71 +++ src/simulator/scheduler-list.cc | 107 ++++ src/simulator/scheduler-list.h | 57 +++ src/simulator/scheduler-map.cc | 112 +++++ src/simulator/scheduler-map.h | 59 +++ src/simulator/scheduler.cc | 46 ++ src/simulator/scheduler.h | 54 ++ src/simulator/simulator.cc | 544 ++++++++++++++++++++ src/simulator/simulator.h | 231 +++++++++ 101 files changed, 12664 insertions(+) create mode 100644 src/common/buffer.cc create mode 100644 src/common/buffer.h create mode 100644 src/common/callback-logger.h create mode 100644 src/common/chunk-constant-data.cc create mode 100644 src/common/chunk-constant-data.h create mode 100644 src/common/chunk-llc-snap.cc create mode 100644 src/common/chunk-llc-snap.h create mode 100644 src/common/chunk-utils.cc create mode 100644 src/common/chunk-utils.h create mode 100644 src/common/chunk.cc create mode 100644 src/common/chunk.h create mode 100644 src/common/count-ptr-holder.tcc create mode 100644 src/common/data-writer.cc create mode 100644 src/common/data-writer.h create mode 100644 src/common/f-traced-variable.tcc create mode 100644 src/common/ipv4-address.cc create mode 100644 src/common/ipv4-address.h create mode 100644 src/common/ipv4-network-interface.cc create mode 100644 src/common/ipv4-network-interface.h create mode 100644 src/common/llc-snap-encapsulation.cc create mode 100644 src/common/llc-snap-encapsulation.h create mode 100644 src/common/mac-address-factory.cc create mode 100644 src/common/mac-address-factory.h create mode 100644 src/common/mac-address.cc create mode 100644 src/common/mac-address.h create mode 100644 src/common/mac-network-interface.cc create mode 100644 src/common/mac-network-interface.h create mode 100644 src/common/packet-logger.cc create mode 100644 src/common/packet-logger.h create mode 100644 src/common/packet.cc create mode 100644 src/common/packet.h create mode 100644 src/common/pcap-writer.cc create mode 100644 src/common/pcap-writer.h create mode 100644 src/common/population-analysis.cc create mode 100644 src/common/population-analysis.h create mode 100644 src/common/position.cc create mode 100644 src/common/position.h create mode 100644 src/common/random-uniform-mrg32k3a.cc create mode 100644 src/common/random-uniform.h create mode 100644 src/common/ref-ptr.h create mode 100644 src/common/rng-mrg32k3a.cc create mode 100644 src/common/rng-mrg32k3a.h create mode 100644 src/common/seed-generator-mrg32k3a.cc create mode 100644 src/common/seed-generator.h create mode 100644 src/common/sgi-hashmap.h create mode 100644 src/common/si-traced-variable.tcc create mode 100644 src/common/static-position.cc create mode 100644 src/common/static-position.h create mode 100644 src/common/static-speed-position.cc create mode 100644 src/common/static-speed-position.h create mode 100644 src/common/tags.cc create mode 100644 src/common/tags.h create mode 100644 src/common/timeout.cc create mode 100644 src/common/timeout.h create mode 100644 src/common/trace-container.cc create mode 100644 src/common/trace-container.h create mode 100644 src/common/trace-stream-test.cc create mode 100644 src/common/trace-stream.h create mode 100644 src/common/traced-variable-test.cc create mode 100644 src/common/ui-traced-variable.tcc create mode 100644 src/common/utils.cc create mode 100644 src/common/utils.h create mode 100644 src/core/callback-test.cc create mode 100644 src/core/callback.h create mode 100644 src/core/exec-commands.h create mode 100644 src/core/reference-list-test.cc create mode 100644 src/core/reference-list.h create mode 100644 src/core/system-file.h create mode 100644 src/core/system-mutex.h create mode 100644 src/core/system-semaphore.h create mode 100644 src/core/system-thread.h create mode 100644 src/core/test.cc create mode 100644 src/core/test.h create mode 100644 src/core/unix-exec-commands.cc create mode 100644 src/core/unix-system-file.cc create mode 100644 src/core/unix-system-mutex.cc create mode 100644 src/core/unix-system-semaphore.cc create mode 100644 src/core/unix-system-thread.cc create mode 100644 src/core/unix-wall-clock-ms.cc create mode 100644 src/core/wall-clock-ms.h create mode 100644 src/core/win32-system-file.cc create mode 100644 src/core/win32-system-mutex.cc create mode 100644 src/core/win32-system-semaphore.cc create mode 100644 src/core/win32-system-thread.cc create mode 100644 src/core/win32-wall-clock-ms.cc create mode 100644 src/simulator/event-impl.cc create mode 100644 src/simulator/event-impl.h create mode 100644 src/simulator/event-tcc-test.cc create mode 100644 src/simulator/event-tcc.cc create mode 100644 src/simulator/event.h create mode 100644 src/simulator/event.tcc create mode 100644 src/simulator/scheduler-heap.cc create mode 100644 src/simulator/scheduler-heap.h create mode 100644 src/simulator/scheduler-list.cc create mode 100644 src/simulator/scheduler-list.h create mode 100644 src/simulator/scheduler-map.cc create mode 100644 src/simulator/scheduler-map.h create mode 100644 src/simulator/scheduler.cc create mode 100644 src/simulator/scheduler.h create mode 100644 src/simulator/simulator.cc create mode 100644 src/simulator/simulator.h diff --git a/src/common/buffer.cc b/src/common/buffer.cc new file mode 100644 index 000000000..b787fa5f1 --- /dev/null +++ b/src/common/buffer.cc @@ -0,0 +1,595 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "buffer.h" +#include + +#include +//#define TRACE(x) std::cout << x << std::endl; +#define TRACE(x) + +namespace yans { + +Buffer::BufferDataList Buffer::m_free_list; +uint32_t Buffer::m_max_total_add_start = 0; +uint32_t Buffer::m_max_total_add_end = 0; + +struct Buffer::BufferData * +Buffer::allocate (uint32_t req_size, uint32_t req_start) +{ + if (req_size == 0) { + req_size = 1; + } + assert (req_size >= 1); + uint32_t size = req_size - 1 + sizeof (struct Buffer::BufferData); + uint8_t *b = new uint8_t [size]; + struct BufferData *data = reinterpret_cast(b); + data->m_size = req_size; + data->m_initial_start = req_start; + data->m_dirty_start = req_start; + data->m_dirty_size = 0; + data->m_count = 1; + return data; +} + +void +Buffer::deallocate (struct Buffer::BufferData *data) +{ + uint8_t *buf = reinterpret_cast (data); + delete [] buf; +} +#ifdef USE_FREE_LIST +void +Buffer::recycle (struct Buffer::BufferData *data) +{ + assert (data->m_count == 0); + /* get rid of it if it is too small for later reuse. */ + if (data->m_size < (Buffer::m_max_total_add_start + Buffer::m_max_total_add_end)) { + Buffer::deallocate (data); + return; + } + /* feed into free list */ + if (Buffer::m_free_list.size () > 1000) { + Buffer::deallocate (data); + } else { + Buffer::m_free_list.push_back (data); + } +} + +Buffer::BufferData * +Buffer::create (void) +{ + /* try to find a buffer correctly sized. */ + while (!Buffer::m_free_list.empty ()) { + struct Buffer::BufferData *data = Buffer::m_free_list.back (); + Buffer::m_free_list.pop_back (); + if (data->m_size >= (m_max_total_add_start + m_max_total_add_end)) { + data->m_initial_start = m_max_total_add_start; + data->m_dirty_start = m_max_total_add_start; + data->m_dirty_size = 0; + data->m_count = 1; + return data; + } + Buffer::deallocate (data); + } + struct Buffer::BufferData *data = Buffer::allocate (m_max_total_add_start+m_max_total_add_end, + m_max_total_add_start); + assert (data->m_count == 1); + return data; +} +#else +void +Buffer::recycle (struct Buffer::BufferData *data) +{ + Buffer::deallocate (data); +} + +Buffer::BufferData * +Buffer::create (void) +{ + return Buffer::allocate (m_max_total_add_start+m_max_total_add_end, + m_max_total_add_start); +} +#endif + +}; // namespace yans + + +#include + +namespace yans { + + +void +Buffer::add_at_start (uint32_t start) +{ + assert (m_start <= m_data->m_initial_start); + bool is_dirty = m_data->m_count > 1 && m_start > m_data->m_dirty_start; + if (m_start >= start && !is_dirty) { + /* enough space in the buffer and not dirty. */ + m_start -= start; + m_size += start; + } else if (m_size + start <= m_data->m_size && !is_dirty) { + /* enough space but need to move data around to fit new data */ + memmove (m_data->m_data + start, get_start (), m_size); + assert (start > m_start); + m_data->m_initial_start += start; + m_start = 0; + m_size += start; + } else if (m_start < start) { + /* not enough space in buffer */ + uint32_t new_size = m_size + start; + struct Buffer::BufferData *new_data = Buffer::allocate (new_size, 0); + memcpy (new_data->m_data + start, get_start (), m_size); + new_data->m_initial_start = m_data->m_initial_start + start; + m_data->m_count--; + if (m_data->m_count == 0) { + Buffer::deallocate (m_data); + } + m_data = new_data; + m_start = 0; + m_size = new_size; + } else { + /* enough space in the buffer but it is dirty ! */ + assert (is_dirty); + struct Buffer::BufferData *new_data = Buffer::create (); + memcpy (new_data->m_data + m_start, get_start (), m_size); + new_data->m_initial_start = m_data->m_initial_start; + m_data->m_count--; + if (m_data->m_count == 0) { + recycle (m_data); + } + m_data = new_data; + m_start -= start; + m_size += start; + } + // update dirty area + m_data->m_dirty_start = m_start; + m_data->m_dirty_size = m_size; + // update m_max_total_add_start + uint32_t added_at_start; + if (m_data->m_initial_start > m_start) { + added_at_start = m_data->m_initial_start - m_start; + } else { + added_at_start = 0; + } + if (added_at_start > m_max_total_add_start) { + m_max_total_add_start = added_at_start; + } + TRACE ("start add="< + +namespace yans { + +class BufferTest: public Test { +private: + bool ensure_written_bytes (Buffer b, uint32_t n, uint8_t array[]); +public: + virtual bool run_tests (void); + BufferTest (); +}; + + +BufferTest::BufferTest () + : Test ("Buffer") {} + +bool +BufferTest::ensure_written_bytes (Buffer b, uint32_t n, uint8_t array[]) +{ + bool success = true; + uint8_t *expected = array; + uint8_t *got; + got = b.peek_data (); + for (uint32_t j = 0; j < n; j++) { + if (got[j] != expected[j]) { + success = false; + } + } + if (!success) { + failure () << "Buffer -- "; + failure () << "expected: n="; + failure () << n << ", "; + failure ().setf (std::ios::hex, std::ios::basefield); + for (uint32_t j = 0; j < n; j++) { + failure () << (uint16_t)expected[j] << " "; + } + failure ().setf (std::ios::dec, std::ios::basefield); + failure () << "got: "; + failure ().setf (std::ios::hex, std::ios::basefield); + for (uint32_t j = 0; j < n; j++) { + failure () << (uint16_t)got[j] << " "; + } + failure () << std::endl; + } + return success; +} + +/* Note: works only when variadic macros are + * available which is the case for gcc. + * XXX + */ +#define ENSURE_WRITTEN_BYTES(buffer, n, ...) \ +{ \ + uint8_t bytes[] = {__VA_ARGS__}; \ + if (!ensure_written_bytes (buffer, n , bytes)) { \ + ok = false; \ + } \ +} + +bool +BufferTest::run_tests (void) +{ + bool ok = true; + Buffer buffer; + Buffer::Iterator i; + buffer.add_at_start (6); + i = buffer.begin (); + i.write_u8 (0x66); + ENSURE_WRITTEN_BYTES (buffer, 1, 0x66); + i = buffer.begin (); + i.write_u8 (0x67); + ENSURE_WRITTEN_BYTES (buffer, 1, 0x67); + i.write_hton_u16 (0x6568); + i = buffer.begin (); + ENSURE_WRITTEN_BYTES (buffer, 3, 0x67, 0x65, 0x68); + i.write_hton_u16 (0x6369); + ENSURE_WRITTEN_BYTES (buffer, 3, 0x63, 0x69, 0x68); + i.write_hton_u32 (0xdeadbeaf); + ENSURE_WRITTEN_BYTES (buffer, 6, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf); + buffer.add_at_start (2); + i = buffer.begin (); + i.write_u16 (0); + ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf); + buffer.add_at_end (2); + i = buffer.begin (); + i.next (8); + i.write_u16 (0); + ENSURE_WRITTEN_BYTES (buffer, 10, 0, 0, 0x63, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0); + buffer.remove_at_start (3); + i = buffer.begin (); + ENSURE_WRITTEN_BYTES (buffer, 7, 0x69, 0xde, 0xad, 0xbe, 0xaf, 0, 0); + buffer.remove_at_end (4); + i = buffer.begin (); + ENSURE_WRITTEN_BYTES (buffer, 3, 0x69, 0xde, 0xad); + buffer.add_at_start (1); + i = buffer.begin (); + i.write_u8 (0xff); + ENSURE_WRITTEN_BYTES (buffer, 4, 0xff, 0x69, 0xde, 0xad); + buffer.add_at_end (1); + i = buffer.begin (); + i.next (4); + i.write_u8 (0xff); + i.prev (2); + uint16_t saved = i.read_u16 (); + i.prev (2); + i.write_hton_u16 (0xff00); + i.prev (2); + if (i.read_ntoh_u16 () != 0xff00) { + ok = false; + } + i.prev (2); + i.write_u16 (saved); + ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0x69, 0xde, 0xad, 0xff); + Buffer o = buffer; + ENSURE_WRITTEN_BYTES (o, 5, 0xff, 0x69, 0xde, 0xad, 0xff); + o.add_at_start (1); + i = o.begin (); + i.write_u8 (0xfe); + ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff); + buffer.add_at_start (2); + i = buffer.begin (); + i.write_u8 (0xfd); + i.write_u8 (0xfd); + ENSURE_WRITTEN_BYTES (o, 6, 0xfe, 0xff, 0x69, 0xde, 0xad, 0xff); + ENSURE_WRITTEN_BYTES (buffer, 7, 0xfd, 0xfd, 0xff, 0x69, 0xde, 0xad, 0xff); + + // test self-assignment + { + Buffer a = o; + a = a; + } + + // test remove start. + buffer = Buffer (5); + ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0); + buffer.remove_at_start (1); + ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0); + buffer.add_at_start (1); + buffer.begin ().write_u8 (0xff); + ENSURE_WRITTEN_BYTES (buffer, 5, 0xff, 0, 0, 0, 0); + buffer.remove_at_start(3); + ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0); + buffer.add_at_start (4); + buffer.begin ().write_hton_u32 (0xdeadbeaf); + ENSURE_WRITTEN_BYTES (buffer, 6, 0xde, 0xad, 0xbe, 0xaf, 0, 0); + buffer.remove_at_start (2); + ENSURE_WRITTEN_BYTES (buffer, 4, 0xbe, 0xaf, 0, 0); + buffer.add_at_end (4); + i = buffer.begin (); + i.next (4); + i.write_hton_u32 (0xdeadbeaf); + ENSURE_WRITTEN_BYTES (buffer, 8, 0xbe, 0xaf, 0, 0, 0xde, 0xad, 0xbe, 0xaf); + buffer.remove_at_start (5); + ENSURE_WRITTEN_BYTES (buffer, 3, 0xad, 0xbe, 0xaf); + // test remove end + buffer = Buffer (5); + ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0); + buffer.remove_at_end (1); + ENSURE_WRITTEN_BYTES (buffer, 4, 0, 0, 0, 0); + buffer.add_at_end (2); + i = buffer.begin (); + i.next (4); + i.write_u8 (0xab); + i.write_u8 (0xac); + ENSURE_WRITTEN_BYTES (buffer, 6, 0, 0, 0, 0, 0xab, 0xac); + buffer.remove_at_end (1); + ENSURE_WRITTEN_BYTES (buffer, 5, 0, 0, 0, 0, 0xab); + buffer.remove_at_end (3); + ENSURE_WRITTEN_BYTES (buffer, 2, 0, 0); + buffer.add_at_end (6); + i = buffer.begin (); + i.next (2); + i.write_u8 (0xac); + i.write_u8 (0xad); + i.write_u8 (0xae); + i.write_u8 (0xaf); + i.write_u8 (0xba); + i.write_u8 (0xbb); + ENSURE_WRITTEN_BYTES (buffer, 8, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb); + buffer.add_at_start (3); + i = buffer.begin (); + i.write_u8 (0x30); + i.write_u8 (0x31); + i.write_u8 (0x32); + ENSURE_WRITTEN_BYTES (buffer, 11, 0x30, 0x31, 0x32, 0, 0, 0xac, 0xad, 0xae, 0xaf, 0xba, 0xbb); + buffer.remove_at_end (9); + ENSURE_WRITTEN_BYTES (buffer, 2, 0x30, 0x31); + buffer = Buffer (3); + buffer.add_at_end (2); + i = buffer.begin (); + i.next (3); + i.write_hton_u16 (0xabcd); + buffer.add_at_start (1); + buffer.begin ().write_u8 (0x21); + ENSURE_WRITTEN_BYTES (buffer, 6, 0x21, 0, 0, 0, 0xab, 0xcd); + buffer.remove_at_end (8); + if (buffer.get_size () != 0) { + ok = false; + } + + + + + return ok; +} + + + +static BufferTest g_buffer_test; + +}; // namespace yans + +#endif /* RUN_SELF_TESTS */ + + diff --git a/src/common/buffer.h b/src/common/buffer.h new file mode 100644 index 000000000..f3fbc25ef --- /dev/null +++ b/src/common/buffer.h @@ -0,0 +1,690 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef BUFFER_H +#define BUFFER_H + +#include +#include + +namespace yans { + +/** + * \brief automatically resized byte buffer + * + * This represents a buffer of bytes. Its size is + * automatically adjusted to hold any data prepended + * or appended by the user. Its implementation is optimized + * to ensure that the number of buffer resizes is minimized, + * by creating new Buffers of the maximum size ever used. + * The correct maximum size is learned at runtime during use by + * recording the maximum size of each packet. + */ +class Buffer { +public: + /** + * \brief iterator in a Buffer instance + */ + class Iterator { + public: + inline Iterator (); + /** + * go forward by one byte + */ + inline void next (void); + /** + * go backward by one byte + */ + inline void prev (void); + /** + * \param delta number of bytes to go forward + */ + inline void next (uint32_t delta); + /** + * \param delta number of bytes to go backward + */ + inline void prev (uint32_t delta); + /** + * \param o the second iterator + * \return number of bytes included between the two iterators + * + * This method works only if the two iterators point + * to the same underlying buffer. Debug builds ensure + * this with an assert. + */ + inline int32_t get_distance_from (Iterator const &o) const; + + /** + * \return true if this iterator points to the end of the byte array. + * false otherwise. + */ + inline bool is_end (void) const; + /** + * \return true if this iterator points to the start of the byte array. + * false otherwise. + */ + inline bool is_start (void) const; + + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by one byte. + */ + inline void write_u8 (uint8_t data); + /** + * \param data data to write in buffer + * \param len number of times data must be written in buffer + * + * Write the data in buffer len times and avance the iterator position + * by len byte. + */ + inline void write_u8 (uint8_t data, uint32_t len); + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by two bytes. The format of the data written in the byte + * buffer is non-portable. We only ensure that read_u16 will + * return exactly what we wrote with write_u16 if the program + * is run on the same machine. + */ + inline void write_u16 (uint16_t data); + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by four bytes. The format of the data written in the byte + * buffer is non-portable. We only ensure that read_u32 will + * return exactly what we wrote with write_u32 if the program + * is run on the same machine. + */ + inline void write_u32 (uint32_t data); + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by eight bytes. The format of the data written in the byte + * buffer is non-portable. We only ensure that read_u64 will + * return exactly what we wrote with write_u64 if the program + * is run on the same machine. + */ + inline void write_u64 (uint64_t data); + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by two bytes. The data is written in network order and the + * input data is expected to be in host order. + */ + inline void write_hton_u16 (uint16_t data); + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by four bytes. The data is written in network order and the + * input data is expected to be in host order. + */ + inline void write_hton_u32 (uint32_t data); + /** + * \param data data to write in buffer + * + * Write the data in buffer and avance the iterator position + * by eight bytes. The data is written in network order and the + * input data is expected to be in host order. + */ + inline void write_hton_u64 (uint64_t data); + /** + * \param buffer a byte buffer to copy in the internal buffer. + * \param size number of bytes to copy. + * + * Write the data in buffer and avance the iterator position + * by size bytes. + */ + inline void write (uint8_t const*buffer, uint16_t size); + /** + * \param start the start of the data to copy + * \param end the end of the data to copy + * + * Write the data delimited by start and end in internal buffer + * and avance the iterator position by the number of bytes + * copied. + * The input interators _must_ not point to the same Buffer as + * we do to avoid overlapping copies. This is enforced + * in debug builds by asserts. + */ + inline void write (Iterator start, Iterator end); + + /** + * \return the byte read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + */ + inline uint8_t read_u8 (void); + /** + * \return the two bytes read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + * The data is read in the format written by write_u16. + */ + inline uint16_t read_u16 (void); + /** + * \return the four bytes read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + * The data is read in the format written by write_u32. + */ + inline uint32_t read_u32 (void); + /** + * \return the eight bytes read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + * The data is read in the format written by write_u64. + */ + inline uint64_t read_u64 (void); + /** + * \return the two bytes read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + * The data is read in network format and return in host format. + */ + inline uint16_t read_ntoh_u16 (void); + /** + * \return the four bytes read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + * The data is read in network format and return in host format. + */ + inline uint32_t read_ntoh_u32 (void); + /** + * \return the eight bytes read in the buffer. + * + * Read data and advance the Iterator by the number of bytes + * read. + * The data is read in network format and return in host format. + */ + inline uint64_t read_ntoh_u64 (void); + /** + * \param buffer buffer to copy data into + * \param size number of bytes to copy + * + * Copy size bytes of data from the internal buffer to the + * input buffer and avance the Iterator by the number of + * bytes read. + */ + inline void read (uint8_t *buffer, uint16_t size); + private: + friend class Buffer; + inline Iterator (Buffer const*buffer, uint32_t m_current); + inline uint32_t get_index (uint32_t n); + uint32_t m_zero_start; + uint32_t m_zero_end; + uint32_t m_data_end; + uint32_t m_current; + uint8_t *m_data; + }; + + /** + * \return the number of bytes stored in this buffer. + */ + inline uint32_t get_size (void) const; + + /** + * \return a pointer to the start of the internal + * byte buffer. + * + * The returned pointer points to an area of + * memory which is yans::Buffer::get_size () bytes big. + * Please, try to never ever use this method. It is really + * evil and is present only for a few specific uses. + */ + uint8_t *peek_data (void) const; + + /** + * \param start size to reserve + * + * Add bytes at the start of the Buffer. The + * content of these bytes is undefined but debugging + * builds initialize them to 0x33. + * Any call to this method invalidates any Iterator + * pointing to this Buffer. + */ + void add_at_start (uint32_t start); + /** + * \param end size to reserve + * + * Add bytes at the end of the Buffer. The + * content of these bytes is undefined but debugging + * builds initialize them to 0x33. + * Any call to this method invalidates any Iterator + * pointing to this Buffer. + */ + void add_at_end (uint32_t end); + /** + * \param start size to remove + * + * Remove bytes at the start of the Buffer. + * Any call to this method invalidates any Iterator + * pointing to this Buffer. + */ + void remove_at_start (uint32_t start); + /** + * \param end size to remove + * + * Remove bytes at the end of the Buffer. + * Any call to this method invalidates any Iterator + * pointing to this Buffer. + */ + void remove_at_end (uint32_t end); + + /** + * \param start offset from start of packet + * \param length + * + * \return a fragment of size length starting at offset + * start. + */ + Buffer create_fragment (uint32_t start, uint32_t length) const; + + /** + * \return an Iterator which points to the + * start of this Buffer. + */ + inline Buffer::Iterator begin (void) const; + /** + * \return an Iterator which points to the + * end of this Buffer. + */ + inline Buffer::Iterator end (void) const; + + inline Buffer (Buffer const &o); + inline Buffer &operator = (Buffer const &o); + inline Buffer (); + inline Buffer (uint32_t data_size); + inline ~Buffer (); +private: + struct BufferData { + uint32_t m_count; + uint32_t m_size; + uint32_t m_initial_start; + uint32_t m_dirty_start; + uint32_t m_dirty_size; + uint8_t m_data[1]; + }; + typedef std::vector BufferDataList; + + inline uint8_t *get_start (void) const; + void transform_into_real_buffer (void) const; + static void recycle (struct Buffer::BufferData *data); + static struct Buffer::BufferData *create (void); + static struct Buffer::BufferData *allocate (uint32_t size, uint32_t start); + static void deallocate (struct Buffer::BufferData *data); + + static BufferDataList m_free_list; + static uint32_t m_max_total_add_start; + static uint32_t m_max_total_add_end; + + struct BufferData *m_data; + uint32_t m_zero_area_size; + uint32_t m_start; + uint32_t m_size; +}; + +}; // namespace yans + +#include + +namespace yans { + +Buffer::Buffer () + : m_data (Buffer::create ()), + m_zero_area_size (0), + m_start (m_max_total_add_start), + m_size (0) +{ + if (m_start > m_data->m_size) { + m_start = 0; + } + assert (m_start <= m_data->m_size); +} + +Buffer::Buffer (uint32_t data_size) + : m_data (Buffer::create ()), + m_zero_area_size (data_size), + m_start (m_max_total_add_start), + m_size (0) +{ + if (m_start > m_data->m_size) { + m_start = 0; + } + assert (m_start <= m_data->m_size); +} + + +Buffer::Buffer (Buffer const&o) + : m_data (o.m_data), + m_zero_area_size (o.m_zero_area_size), + m_start (o.m_start), + m_size (o.m_size) +{ + m_data->m_count++; + assert (m_start <= m_data->m_size); +} + +Buffer & +Buffer::operator = (Buffer const&o) +{ + if (m_data != o.m_data) { + // not assignment to self. + m_data->m_count--; + if (m_data->m_count == 0) { + recycle (m_data); + } + m_data = o.m_data; + m_data->m_count++; + } + m_zero_area_size = o.m_zero_area_size; + m_start = o.m_start; + m_size = o.m_size; + assert (m_start <= m_data->m_size); + return *this; +} + +Buffer::~Buffer () +{ + m_data->m_count--; + if (m_data->m_count == 0) { + recycle (m_data); + } +} + + +uint8_t * +Buffer::get_start (void) const +{ + return m_data->m_data + m_start; +} + +uint32_t +Buffer::get_size (void) const +{ + return m_size + m_zero_area_size; +} + +Buffer::Iterator +Buffer::begin (void) const +{ + return Buffer::Iterator (this, 0); +} +Buffer::Iterator +Buffer::end (void) const +{ + return Buffer::Iterator (this, get_size ()); +} + + +Buffer::Iterator::Iterator () + : m_zero_start (0), + m_zero_end (0), + m_data_end (0), + m_current (0), + m_data (0) +{} +Buffer::Iterator::Iterator (Buffer const*buffer, uint32_t current) + : m_zero_start (buffer->m_data->m_initial_start-buffer->m_start), + m_zero_end (m_zero_start+buffer->m_zero_area_size), + m_data_end (buffer->get_size ()), + m_current (current), + m_data (buffer->m_data->m_data+buffer->m_start) +{} + +void +Buffer::Iterator::next (void) +{ + assert (m_current + 1 <= m_data_end); + m_current++; +} +void +Buffer::Iterator::prev (void) +{ + assert (m_current >= 1); + m_current--; +} +void +Buffer::Iterator::next (uint32_t delta) +{ + assert (m_current + delta <= m_data_end); + m_current += delta; +} +void +Buffer::Iterator::prev (uint32_t delta) +{ + assert (m_current >= delta); + m_current -= delta; +} +int32_t +Buffer::Iterator::get_distance_from (Iterator const &o) const +{ + assert (m_data == o.m_data); + int32_t start = m_current; + int32_t end = o.m_current; + return end - start; +} + +bool +Buffer::Iterator::is_end (void) const +{ + return m_current == m_data_end; +} +bool +Buffer::Iterator::is_start (void) const +{ + return m_current == 0; +} + +uint32_t +Buffer::Iterator::get_index (uint32_t n) +{ + assert ( + (m_current + n <= m_data_end) && + ((m_current + n <= m_zero_start) || + (m_current >= m_zero_end)) + ); + uint32_t index; + if (m_current < m_zero_start) { + index = m_current; + } else { + index = m_current - (m_zero_end-m_zero_start); + } + return index; +} + + +void +Buffer::Iterator::write (Iterator start, Iterator end) +{ + assert (start.m_data == end.m_data); + assert (start.m_current <= end.m_current); + assert (m_data != start.m_data); + uint32_t size = end.m_current - start.m_current; + uint8_t *src = start.m_data + start.get_index (size); + uint8_t *dest = m_data + get_index (size); + memcpy (dest, src, size); + m_current += size; +} + +void +Buffer::Iterator::write_u8 (uint8_t data, uint32_t len) +{ + uint8_t *current = m_data + get_index (len); + memset (current, data, len); + m_current += len; +} +void +Buffer::Iterator::write_u8 (uint8_t data) +{ + m_data[get_index (1)] = data; + m_current++; +} +void +Buffer::Iterator::write_u16 (uint16_t data) +{ + uint16_t *buffer = (uint16_t *)(m_data + get_index (2)); + *buffer = data; + m_current += 2; +} +void +Buffer::Iterator::write_u32 (uint32_t data) +{ + uint32_t *buffer = (uint32_t *)(m_data + get_index (4)); + *buffer = data; + m_current += 4; +} +void +Buffer::Iterator::write_u64 (uint64_t data) +{ + uint64_t *buffer = (uint64_t *)(m_data + get_index (8)); + *buffer = data; + m_current += 8; +} +void +Buffer::Iterator::write_hton_u16 (uint16_t data) +{ + uint8_t *current = m_data + get_index (2); + *(current+0) = (data >> 8) & 0xff; + *(current+1) = (data >> 0) & 0xff; + m_current += 2; +} +void +Buffer::Iterator::write_hton_u32 (uint32_t data) +{ + uint8_t *current = m_data + get_index (4); + *(current+0) = (data >> 24) & 0xff; + *(current+1) = (data >> 16) & 0xff; + *(current+2) = (data >> 8) & 0xff; + *(current+3) = (data >> 0) & 0xff; + m_current += 4; +} +void +Buffer::Iterator::write_hton_u64 (uint64_t data) +{ + uint8_t *current = m_data + get_index (8); + *(current+0) = (data >> 56) & 0xff; + *(current+1) = (data >> 48) & 0xff; + *(current+2) = (data >> 40) & 0xff; + *(current+3) = (data >> 32) & 0xff; + *(current+4) = (data >> 24) & 0xff; + *(current+5) = (data >> 16) & 0xff; + *(current+6) = (data >> 8) & 0xff; + *(current+7) = (data >> 0) & 0xff; + m_current += 8; +} +void +Buffer::Iterator::write (uint8_t const*buffer, uint16_t size) +{ + uint8_t *current = m_data + get_index (size); + memcpy (current, buffer, size); + m_current += size; +} + +uint8_t +Buffer::Iterator::read_u8 (void) +{ + uint8_t data = m_data[get_index(1)]; + m_current++; + return data; +} +uint16_t +Buffer::Iterator::read_u16 (void) +{ + uint16_t *buffer = reinterpret_cast(m_data + get_index (2)); + m_current += 2; + return *buffer; +} +uint32_t +Buffer::Iterator::read_u32 (void) +{ + uint32_t *buffer = reinterpret_cast(m_data + get_index (4)); + m_current += 4; + return *buffer; +} +uint64_t +Buffer::Iterator::read_u64 (void) +{ + uint64_t *buffer = reinterpret_cast(m_data + get_index (8)); + m_current += 8; + return *buffer; +} +uint16_t +Buffer::Iterator::read_ntoh_u16 (void) +{ + uint8_t *current = m_data + get_index (2); + uint16_t retval = 0; + retval |= static_cast (current[0]) << 8; + retval |= static_cast (current[1]) << 0; + m_current += 2; + return retval; +} +uint32_t +Buffer::Iterator::read_ntoh_u32 (void) +{ + uint8_t *current = m_data + get_index (4); + uint32_t retval = 0; + retval |= static_cast (current[0]) << 24; + retval |= static_cast (current[1]) << 16; + retval |= static_cast (current[2]) << 8; + retval |= static_cast (current[3]) << 0; + m_current += 4; + return retval; +} +uint64_t +Buffer::Iterator::read_ntoh_u64 (void) +{ + uint8_t *current = m_data + get_index (8); + uint64_t retval = 0; + retval |= static_cast (current[0]) << 56; + retval |= static_cast (current[1]) << 48; + retval |= static_cast (current[2]) << 40; + retval |= static_cast (current[3]) << 32; + retval |= static_cast (current[4]) << 24; + retval |= static_cast (current[5]) << 16; + retval |= static_cast (current[6]) << 8; + retval |= static_cast (current[7]) << 0; + m_current += 8; + return retval; +} +void +Buffer::Iterator::read (uint8_t *buffer, uint16_t size) +{ + uint8_t *current = m_data + get_index (size); + memcpy (buffer, current, size); + m_current += size; +} + +}; // namespace yans + + +#endif /* BUFFER_H */ diff --git a/src/common/callback-logger.h b/src/common/callback-logger.h new file mode 100644 index 000000000..18f968aab --- /dev/null +++ b/src/common/callback-logger.h @@ -0,0 +1,84 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef CALLBACK_LOGGER_H +#define CALLBACK_LOGGER_H + +#include "yans/callback.h" + +namespace yans { + +class CallbackLoggerBase {}; + +/** + * \brief log arbitrary number of parameters to a matching yans:Callback + * + * Whenever operator () is invoked on this class, the call and its arguments + * are forwarded to the internal matching yans::Callback. + */ +template +class CallbackLogger : public CallbackLoggerBase{ +public: + CallbackLogger () + : m_callback () {} + void set_callback (Callback callback) { + m_callback = callback; + } + void operator() (void) { + if (!m_callback.is_null ()) { + m_callback (); + } + } + void operator() (T1 a1) { + if (!m_callback.is_null ()) { + m_callback (a1); + } + } + void operator() (T1 a1, T2 a2) { + if (!m_callback.is_null ()) { + m_callback (a1,a2); + } + } + void operator() (T1 a1, T2 a2, T3 a3) { + if (!m_callback.is_null ()) { + m_callback (a1,a2,a3); + } + } + void operator() (T1 a1, T2 a2, T3 a3, T4 a4) { + if (!m_callback.is_null ()) { + m_callback (a1,a2,a3,a4); + } + } + void operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) { + if (!m_callback.is_null ()) { + m_callback (a1,a2,a3,a4,a5); + } + } + +private: + Callback m_callback; +}; + +}; // namespace yans + +#endif /* CALLBACK_LOGGER_H */ diff --git a/src/common/chunk-constant-data.cc b/src/common/chunk-constant-data.cc new file mode 100644 index 000000000..e2c72ef22 --- /dev/null +++ b/src/common/chunk-constant-data.cc @@ -0,0 +1,63 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "chunk-constant-data.h" + +namespace yans { + +ChunkConstantData::ChunkConstantData (uint32_t len, uint8_t data) + : m_len (len), m_data (data) +{} + +ChunkConstantData::~ChunkConstantData () +{} + + +void +ChunkConstantData::print (std::ostream *os) const +{ + *os << "(constant data)" + << " len=" << m_len + << ", data=" << m_data; +} + +void +ChunkConstantData::add_to (Buffer *buffer) const +{ + buffer->add_at_start (m_len); +#ifndef NDEBUG + buffer->begin ().write_u8 (m_data, m_len); +#endif +} +void +ChunkConstantData::peek_from (Buffer const *buffer) +{ + m_len = buffer->get_size (); + m_data = buffer->begin ().read_u8 (); +} +void +ChunkConstantData::remove_from (Buffer *buffer) +{ + buffer->remove_at_start (m_len); +} + + +}; // namespace yans diff --git a/src/common/chunk-constant-data.h b/src/common/chunk-constant-data.h new file mode 100644 index 000000000..d246a5659 --- /dev/null +++ b/src/common/chunk-constant-data.h @@ -0,0 +1,47 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef CHUNK_CONSTANT_DATA_H +#define CHUNK_CONSTANT_DATA_H + +#include "chunk.h" +#include + +namespace yans { + + +class ChunkConstantData : public Chunk { +public: + ChunkConstantData (uint32_t len, uint8_t data); + ~ChunkConstantData (); + +private: + virtual void print (std::ostream *os) const; + virtual void add_to (Buffer *buffer) const; + virtual void peek_from (Buffer const *buffer); + virtual void remove_from (Buffer *buffer); + uint32_t m_len; + uint8_t m_data; +}; + +}; // namespace yans + +#endif /* CHUNK_CONSTANT_DATA_H */ diff --git a/src/common/chunk-llc-snap.cc b/src/common/chunk-llc-snap.cc new file mode 100644 index 000000000..b8d8eade1 --- /dev/null +++ b/src/common/chunk-llc-snap.cc @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "chunk-llc-snap.h" +#include + +#define noTRACE_CHUNK_LLC_SNAP 1 + +#ifdef TRACE_CHUNK_LLC_SNAP +#include +#include "simulator.h" +# define TRACE(x) \ +std::cout << "CHUNK LLCSNAP TRACE " << Simulator::now_s () << " " << x << std::endl; +#else /* TRACE_CHUNK_LLC_SNAP */ +# define TRACE(format,...) +#endif /* TRACE_CHUNK_LLC_SNAP */ + + +namespace yans { + +ChunkLlcSnap::ChunkLlcSnap () +{} + +ChunkLlcSnap::~ChunkLlcSnap () +{} +void +ChunkLlcSnap::set_type (enum Type type) +{ + m_ether_type = type; +} +enum ChunkLlcSnap::Type +ChunkLlcSnap::get_type (void) +{ + return (enum ChunkLlcSnap::Type) m_ether_type; +} + +uint32_t +ChunkLlcSnap::get_size (void) const +{ + return 1 + 1 + 1 + 3 + 2; +} +void +ChunkLlcSnap::print (std::ostream *os) const +{ + *os << "(mac)" + << " EtherType: "; + os->setf (std::ios::hex, std::ios::basefield); + *os << m_ether_type; + os->setf (std::ios::dec, std::ios::basefield); +} + +void +ChunkLlcSnap::add_to (Buffer *buffer) const +{ + buffer->add_at_start (get_size ()); + Buffer::Iterator i = buffer->begin (); + uint8_t buf[] = {0xaa, 0xaa, 0x03, 0, 0, 0}; + i.write (buf, 6); + i.write_hton_u16 (m_ether_type); +} +void +ChunkLlcSnap::peek_from (Buffer const *buffer) +{ + Buffer::Iterator i = buffer->begin (); + i.next (5+1); + m_ether_type = i.read_ntoh_u16 (); +} +void +ChunkLlcSnap::remove_from (Buffer *buffer) +{ + buffer->remove_at_start (get_size ()); +} + + + +}; // namespace yans diff --git a/src/common/chunk-llc-snap.h b/src/common/chunk-llc-snap.h new file mode 100644 index 000000000..793dd36a8 --- /dev/null +++ b/src/common/chunk-llc-snap.h @@ -0,0 +1,55 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef CHUNK_LLC_SNAP_H +#define CHUNK_LLC_SNAP_H + +#include "chunk.h" +#include + +namespace yans { + +class ChunkLlcSnap : public Chunk { + public: + ChunkLlcSnap (); + virtual ~ChunkLlcSnap (); + + enum Type { + TYPE_IPV4 = 0x0800, + TYPE_ARP = 0x0806 + }; + + void set_type (enum Type type); + enum Type get_type (void); + + uint32_t get_size (void) const; + +private: + virtual void print (std::ostream *os) const; + virtual void add_to (Buffer *buffer) const; + virtual void peek_from (Buffer const *buffer); + virtual void remove_from (Buffer *buffer); + uint16_t m_ether_type; +}; + +}; // namespace yans + +#endif /* CHUNK_LLC_SNAP_H */ diff --git a/src/common/chunk-utils.cc b/src/common/chunk-utils.cc new file mode 100644 index 000000000..462839f3d --- /dev/null +++ b/src/common/chunk-utils.cc @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "chunk-utils.h" + +namespace yans { + +void write_to (Buffer::Iterator &i, Ipv4Address ad) +{ + i.write_hton_u32 (ad.get_host_order ()); +} +void write_to (Buffer::Iterator &i, MacAddress ad) +{ + uint8_t mac[6]; + ad.peek (mac); + i.write (mac, 6); +} + +void read_from (Buffer::Iterator &i, Ipv4Address &ad) +{ + ad.set_host_order (i.read_ntoh_u32 ()); +} +void read_from (Buffer::Iterator &i, MacAddress &ad) +{ + uint8_t mac[6]; + i.read (mac, 6); + ad.set (mac); +} + + + +}; // namespace yans diff --git a/src/common/chunk-utils.h b/src/common/chunk-utils.h new file mode 100644 index 000000000..04b38a6d9 --- /dev/null +++ b/src/common/chunk-utils.h @@ -0,0 +1,38 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef CHUNK_UTILS_H +#define CHUNK_UTILS_H + +#include "buffer.h" +#include "ipv4-address.h" +#include "mac-address.h" + +namespace yans { + +void write_to (Buffer::Iterator &i, Ipv4Address ad); +void write_to (Buffer::Iterator &i, MacAddress ad); + +void read_from (Buffer::Iterator &i, Ipv4Address &ad); +void read_from (Buffer::Iterator &i, MacAddress &ad); + +}; + +#endif /* CHUNK_UTILS_H */ diff --git a/src/common/chunk.cc b/src/common/chunk.cc new file mode 100644 index 000000000..fcb7a8071 --- /dev/null +++ b/src/common/chunk.cc @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "chunk.h" +#include + +namespace yans { + +Chunk::Chunk () + : m_must_peek_before_remove (false) {} + +void +Chunk::print (std::ostream &os) const +{ + print (&os); +} +void +Chunk::add (Buffer *buffer) const +{ + add_to (buffer); +} +void +Chunk::peek (Buffer const *buffer) +{ + peek_from (buffer); + m_must_peek_before_remove = true; +} +void +Chunk::remove (Buffer *buffer) +{ + assert (m_must_peek_before_remove); + remove_from (buffer); + m_must_peek_before_remove = false; +} + + + +Chunk::~Chunk () +{} + +std::ostream& operator<< (std::ostream& os, Chunk const& chunk) +{ + chunk.print (os); + return os; +} + +}; // namespace yans diff --git a/src/common/chunk.h b/src/common/chunk.h new file mode 100644 index 000000000..daf953c4d --- /dev/null +++ b/src/common/chunk.h @@ -0,0 +1,89 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef CHUNK_H +#define CHUNK_H + +#include +#include +#include "buffer.h" + +namespace yans { + +/** + * \brief Protocol header serialization and deserialization. + * + * Every Protocol header which needs to be inserted and removed + * from a Packet instance must derive from this abstract base class + * and implement the private pure virtual methods defined here. + */ +class Chunk { +public: + Chunk (); + /** + * Derived classes must provided an explicit virtual destructor + */ + virtual ~Chunk () = 0; + + void print (std::ostream &os) const; + + void add (Buffer *buffer) const; + void peek (Buffer const *buffer); + void remove (Buffer *buffer); +private: + bool m_must_peek_before_remove; + /** + * \param os the std output stream in which this + * protocol header must print itself. + */ + virtual void print (std::ostream *os) const = 0; + + /** + * \param buffer the buffer in which the protocol header + * must serialize itself. + * + * This method must: + * - reserve room for its serialized representation in the input buffer + * - serialize itself in this reserved room + */ + virtual void add_to (Buffer *buffer) const = 0; + /** + * \param buffer the buffer from which the protocol header must + * deserialize itself. + * + */ + virtual void peek_from (Buffer const *buffer) = 0; + /** + * \param buffer the buffer from which the protocol header + * must remove itself. + * + * This method must remove its serialized representation + * from the input buffer. This method does not need to deserialize + * the data itself. + */ + virtual void remove_from (Buffer *buffer) = 0; +}; + +std::ostream& operator<< (std::ostream& os, Chunk const& chunk); + +}; // namespace yans + +#endif /* CHUNK_H */ diff --git a/src/common/count-ptr-holder.tcc b/src/common/count-ptr-holder.tcc new file mode 100644 index 000000000..67a0685ed --- /dev/null +++ b/src/common/count-ptr-holder.tcc @@ -0,0 +1,70 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef COUNT_PTR_HOLDER_TCC +#define COUNT_PTR_HOLDER_TCC + +namespace yans { + +template +class CountPtrHolder { +public: + typedef T *real_type; + + CountPtrHolder (T *env) + : m_env (env) { + m_env->ref (); + } + ~CountPtrHolder () { + if (m_env != 0) { + m_env->unref (); + } + } + CountPtrHolder (CountPtrHolder const&o) { + m_env = o.m_env; + m_env->ref (); + } + T *remove (void) { + T *env = m_env; + m_env = 0; + return env; + } +private: + CountPtrHolder (); + CountPtrHolder &operator = (CountPtrHolder const& o); + T *m_env; +}; + +template +CountPtrHolder +make_count_ptr_holder (T *t) { + return CountPtrHolder (t); +} + +template +CountPtrHolder +make_const_count_ptr_holder (T *t) { + return CountPtrHolder (t); +} + +}; // namespace yans + +#endif /* REF_HOLDER_TCC */ diff --git a/src/common/data-writer.cc b/src/common/data-writer.cc new file mode 100644 index 000000000..7aa8d1049 --- /dev/null +++ b/src/common/data-writer.cc @@ -0,0 +1,119 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "data-writer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define noTRACE_DATA_WRITER 1 + +#ifdef TRACE_DATA_WRITER +#include +# define TRACE(x) \ +std::cout << "DATA WRITER TRACE " << this << " " << x << std::endl; +#else /* TRACE_DATA_WRITER */ +# define TRACE(format,...) +#endif /* TRACE_DATA_WRITER */ + +#define BUFFER_SIZE (4096) + + +namespace yans { + +class DataWriterPrivate { +public: + DataWriterPrivate (); + ~DataWriterPrivate (); + + void open (char const *filename); + void write (uint8_t *buffer, uint32_t size); +private: + uint8_t m_data[BUFFER_SIZE]; + uint32_t m_current; + int m_fd; +}; + +DataWriterPrivate::DataWriterPrivate () + : m_current (0) +{} +DataWriterPrivate::~DataWriterPrivate () +{ + ::write (m_fd, m_data, m_current); + ::close (m_fd); +} + + +void +DataWriterPrivate::open (char const *filename) +{ + m_fd = ::open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + assert (m_fd != -1); +} + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif /* min */ + +void +DataWriterPrivate::write (uint8_t *buffer, uint32_t size) +{ + while (size > 0) { + uint32_t to_copy = min (BUFFER_SIZE - m_current, size); + memcpy (m_data + m_current, buffer, to_copy); + size -= to_copy; + m_current += to_copy; + buffer += to_copy; + if (m_current == BUFFER_SIZE) { + ssize_t written = 0; + written = ::write (m_fd, m_data, BUFFER_SIZE); + assert (written == BUFFER_SIZE); + m_current = 0; + } + } +} + +DataWriter::DataWriter () + : m_priv (new DataWriterPrivate ()) +{} +DataWriter::~DataWriter () +{ + delete m_priv; + m_priv = 0; +} + +void +DataWriter::open (char const *filename) +{ + m_priv->open (filename); +} +void +DataWriter::write (uint8_t *buffer, uint32_t size) +{ + m_priv->write (buffer, size); +} + +}; // namespace diff --git a/src/common/data-writer.h b/src/common/data-writer.h new file mode 100644 index 000000000..5d066260c --- /dev/null +++ b/src/common/data-writer.h @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef DATA_WRITER_H +#define DATA_WRITER_H + +#include + +namespace yans { + +class DataWriterPrivate; + +class DataWriter { +public: + DataWriter (); + ~DataWriter (); + + void open (char const *filename); + void write (uint8_t *buffer, uint32_t size); +private: + DataWriterPrivate *m_priv; +}; + +}; //namespace yans + +#endif /* DATA_WRITER_H */ diff --git a/src/common/f-traced-variable.tcc b/src/common/f-traced-variable.tcc new file mode 100644 index 000000000..0bc202432 --- /dev/null +++ b/src/common/f-traced-variable.tcc @@ -0,0 +1,58 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef F_TRACED_VARIABLE_TCC +#define F_TRACED_VARIABLE_TCC + +#include "yans/callback.h" +#include + +namespace yans { + +class FTracedVariableBase { +public: + typedef Callback ChangeNotifyCallback; + + FTracedVariableBase () {} + FTracedVariableBase (FTracedVariableBase const &o) {} + FTracedVariableBase &operator = (FTracedVariableBase const &o) { + return *this; + } + + ~FTracedVariableBase () {} + + void set_callback(ChangeNotifyCallback callback) { + m_callback = callback; + } +protected: + void notify (double old_val, double new_val) { + if (old_val != new_val && !m_callback.is_null ()) { + m_callback (old_val, new_val); + } + } +private: + ChangeNotifyCallback m_callback; +}; + + +}; // namespace yans + +#endif /* F_TRACED_VARIABLE_TCC */ diff --git a/src/common/ipv4-address.cc b/src/common/ipv4-address.cc new file mode 100644 index 000000000..91dcd2cad --- /dev/null +++ b/src/common/ipv4-address.cc @@ -0,0 +1,203 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "utils.h" +#include "ipv4-address.h" + +namespace yans { + +Ipv4Mask::Ipv4Mask () + : m_mask (0x66666666) +{} + +Ipv4Mask::Ipv4Mask (uint32_t mask) + : m_mask (mask) +{} +Ipv4Mask::Ipv4Mask (char const *mask) +{ + m_mask = ascii_to_ipv4_host (mask); +} + +bool +Ipv4Mask::is_equal (Ipv4Mask other) const +{ + if (other.m_mask == m_mask) { + return true; + } else { + return false; + } +} + + +bool +Ipv4Mask::is_match (Ipv4Address a, Ipv4Address b) const +{ + if ((a.get_host_order () & m_mask) == (b.get_host_order () & m_mask)) { + return true; + } else { + return false; + } +} + +uint32_t +Ipv4Mask::get_host_order (void) const +{ + return m_mask; +} +void +Ipv4Mask::set_host_order (uint32_t value) +{ + m_mask = value; +} + +void +Ipv4Mask::print (std::ostream *os) const +{ + *os << ((m_mask >> 24) & 0xff) << "." + << ((m_mask >> 16) & 0xff) << "." + << ((m_mask >> 8) & 0xff) << "." + << ((m_mask >> 0) & 0xff); +} + + +Ipv4Mask +Ipv4Mask::get_loopback (void) +{ + static Ipv4Mask loopback = Ipv4Mask ("255.0.0.0"); + return loopback; +} +Ipv4Mask +Ipv4Mask::get_zero (void) +{ + static Ipv4Mask zero = Ipv4Mask ("0.0.0.0"); + return zero; +} + +Ipv4Address::Ipv4Address () + : m_address (0x66666666) +{} +Ipv4Address::Ipv4Address (uint32_t address) +{ + m_address = address; +} +Ipv4Address::Ipv4Address (char const *address) +{ + m_address = ascii_to_ipv4_host (address); +} + +bool +Ipv4Address::is_equal (Ipv4Address other) const +{ + if (other.m_address == m_address) { + return true; + } else { + return false; + } +} + +bool +Ipv4Address::is_multicast (void) +{ + // XXX + return false; +} + +uint32_t +Ipv4Address::get_host_order (void) const +{ + return m_address; +} +void +Ipv4Address::set_host_order (uint32_t ip) +{ + m_address = ip; +} +void +Ipv4Address::serialize (uint8_t buf[4]) const +{ + buf[0] = (m_address >> 24) & 0xff; + buf[1] = (m_address >> 16) & 0xff; + buf[2] = (m_address >> 8) & 0xff; + buf[3] = (m_address >> 0) & 0xff; +} + +void +Ipv4Address::print (std::ostream *os) const +{ + *os << ((m_address >> 24) & 0xff) << "." + << ((m_address >> 16) & 0xff) << "." + << ((m_address >> 8) & 0xff) << "." + << ((m_address >> 0) & 0xff); +} + + + +Ipv4Address +Ipv4Address::get_zero (void) +{ + static Ipv4Address zero ("0.0.0.0"); + return zero; +} +Ipv4Address +Ipv4Address::get_any (void) +{ + static Ipv4Address any ("0.0.0.0"); + return any; +} +Ipv4Address +Ipv4Address::get_broadcast (void) +{ + static Ipv4Address broadcast ("255.255.255.255"); + return broadcast; +} +Ipv4Address +Ipv4Address::get_loopback (void) +{ + Ipv4Address loopback ("127.0.0.1"); + return loopback; +} + +bool operator == (Ipv4Address const &a, Ipv4Address const &b) +{ + return a.is_equal (b); +} +bool operator != (Ipv4Address const &a, Ipv4Address const &b) +{ + return !a.is_equal (b); +} +size_t Ipv4AddressHash::operator()(Ipv4Address const &x) const +{ + return x.get_host_order (); +} + +std::ostream& operator<< (std::ostream& os, Ipv4Address const& address) +{ + address.print (&os); + return os; +} +std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask) +{ + mask.print (&os); + return os; +} + + +}; // namespace yans diff --git a/src/common/ipv4-address.h b/src/common/ipv4-address.h new file mode 100644 index 000000000..b2267242a --- /dev/null +++ b/src/common/ipv4-address.h @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef IPV4_ADDRESS_H +#define IPV4_ADDRESS_H + +#include +#include + +namespace yans { + +/* Ipv4 addresses are stored in host order in + * this class. + */ +class Ipv4Address { +public: + Ipv4Address (); + /* input address is in host order. */ + Ipv4Address (uint32_t address); + /* input address is in format: + * hhh.xxx.xxx.lll + * where h is the high byte and l the + * low byte + */ + Ipv4Address (char const *address); + + bool is_equal (Ipv4Address other) const; + + /* Using this method is frowned upon. + * Please, do _not_ use this method. + * It is there only for chunk-ipv4. + */ + uint32_t get_host_order (void) const; + void set_host_order (uint32_t ip); + void serialize (uint8_t buf[4]) const; + + void print (std::ostream *os) const; + + bool is_broadcast (void); + bool is_multicast (void); + + static Ipv4Address get_zero (void); + static Ipv4Address get_any (void); + static Ipv4Address get_broadcast (void); + static Ipv4Address get_loopback (void); +private: + uint32_t m_address; +}; + + +class Ipv4Mask { +public: + Ipv4Mask (); + Ipv4Mask (uint32_t mask); + Ipv4Mask (char const *mask); + + bool is_match (Ipv4Address a, Ipv4Address b) const; + + bool is_equal (Ipv4Mask other) const; + + + /* Using this method is frowned upon. + * Please, do _not_ use this method. + */ + uint32_t get_host_order (void) const; + void set_host_order (uint32_t value); + + void print (std::ostream *os) const; + + static Ipv4Mask get_loopback (void); + static Ipv4Mask get_zero (void); +private: + uint32_t m_mask; +}; + +std::ostream& operator<< (std::ostream& os, Ipv4Address const& address); +std::ostream& operator<< (std::ostream& os, Ipv4Mask const& mask); + +bool operator == (Ipv4Address const &a, Ipv4Address const &b); +bool operator != (Ipv4Address const &a, Ipv4Address const &b); +class Ipv4AddressHash : public std::unary_function { +public: + size_t operator()(Ipv4Address const &x) const; +}; +bool operator != (Ipv4Address const &a, Ipv4Address const &b); + +}; // namespace yans + +#endif /* IPV4_ADDRESS_H */ diff --git a/src/common/ipv4-network-interface.cc b/src/common/ipv4-network-interface.cc new file mode 100644 index 000000000..cb3c43de7 --- /dev/null +++ b/src/common/ipv4-network-interface.cc @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "ipv4-network-interface.h" + +namespace yans { + +Ipv4NetworkInterface::~Ipv4NetworkInterface () +{} + +void +Ipv4NetworkInterface::set_address (Ipv4Address ad) +{ + m_address = ad; +} +void +Ipv4NetworkInterface::set_mask (Ipv4Mask mask) +{ + m_mask = mask; +} +uint16_t +Ipv4NetworkInterface::get_mtu (void) const +{ + return real_get_mtu (); +} +Ipv4Mask +Ipv4NetworkInterface::get_mask (void) const +{ + return m_mask; +} +Ipv4Address +Ipv4NetworkInterface::get_address (void) const +{ + return m_address; +} +Ipv4Address +Ipv4NetworkInterface::get_broadcast (void) const +{ + uint32_t mask = m_mask.get_host_order (); + uint32_t address = m_address.get_host_order (); + Ipv4Address broadcast = Ipv4Address (address | (~mask)); + return broadcast; +} + +void +Ipv4NetworkInterface::send (Packet packet, Ipv4Address to) +{ + real_send (packet, to); +} + +void +Ipv4NetworkInterface::set_rx_callback (RxCallback callback) +{ + m_rx_callback = callback; +} + +void +Ipv4NetworkInterface::forward_up (Packet packet) +{ + m_rx_callback (packet, this); +} + + + +}; // namespace yans diff --git a/src/common/ipv4-network-interface.h b/src/common/ipv4-network-interface.h new file mode 100644 index 000000000..1b7b98564 --- /dev/null +++ b/src/common/ipv4-network-interface.h @@ -0,0 +1,59 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef IPV4_NETWORK_INTERFACE +#define IPV4_NETWORK_INTERFACE + +#include "ipv4-address.h" +#include "yans/callback.h" +#include "packet.h" + +namespace yans { + +class Packet; + +class Ipv4NetworkInterface { +public: + typedef Callback RxCallback; + virtual ~Ipv4NetworkInterface () = 0; + + void set_address (Ipv4Address ad); + void set_mask (Ipv4Mask mask); + + uint16_t get_mtu (void) const; + Ipv4Mask get_mask (void) const; + Ipv4Address get_address (void) const; + Ipv4Address get_broadcast (void) const; + + void send (Packet packet, Ipv4Address to); + void set_rx_callback (RxCallback callback); +protected: + void forward_up (Packet packet); +private: + virtual uint16_t real_get_mtu (void) const = 0; + virtual void real_send (Packet packet, Ipv4Address to) = 0; + RxCallback m_rx_callback; + Ipv4Address m_address; + Ipv4Mask m_mask; +}; + +}; // namespace yans + +#endif /* IPV4_NETWORK_INTERFACE */ diff --git a/src/common/llc-snap-encapsulation.cc b/src/common/llc-snap-encapsulation.cc new file mode 100644 index 000000000..538696ec0 --- /dev/null +++ b/src/common/llc-snap-encapsulation.cc @@ -0,0 +1,89 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "llc-snap-encapsulation.h" +#include "chunk-llc-snap.h" +#include "packet.h" +#include "chunk.h" +#include "mac-network-interface.h" +#include + +namespace yans { + +uint32_t +LlcSnapEncapsulation::get_overhead (void) const +{ + ChunkLlcSnap llc; + return llc.get_size (); +} +void +LlcSnapEncapsulation::set_ipv4_callback (RxCallback callback) +{ + m_ipv4_callback = callback; +} +void +LlcSnapEncapsulation::set_arp_callback (RxCallback callback) +{ + m_arp_callback = callback; +} +void +LlcSnapEncapsulation::set_mac_interface (MacNetworkInterface *interface) +{ + m_interface = interface; +} +void +LlcSnapEncapsulation::send_ipv4 (Packet packet, MacAddress to) +{ + ChunkLlcSnap llc; + llc.set_type (ChunkLlcSnap::TYPE_IPV4); + packet.add (&llc); + m_interface->send (packet, to); +} +void +LlcSnapEncapsulation::send_arp (Packet packet, MacAddress to) +{ + ChunkLlcSnap llc; + llc.set_type (ChunkLlcSnap::TYPE_ARP); + packet.add (&llc); + m_interface->send (packet, to); +} + +void +LlcSnapEncapsulation::receive (Packet packet, MacNetworkInterface *interface) +{ + assert (interface == m_interface); + ChunkLlcSnap llc; + packet.peek (&llc); + packet.remove (&llc); + switch (llc.get_type ()) { + case ChunkLlcSnap::TYPE_IPV4: + m_ipv4_callback (packet); + break; + case ChunkLlcSnap::TYPE_ARP: + m_arp_callback (packet); + break; + default: + assert (false); + //NOT REACHED + break; + } +} + +}; // namespace yans diff --git a/src/common/llc-snap-encapsulation.h b/src/common/llc-snap-encapsulation.h new file mode 100644 index 000000000..1bfee9d28 --- /dev/null +++ b/src/common/llc-snap-encapsulation.h @@ -0,0 +1,52 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef LLC_SNAP_ENCAPSULATION +#define LLC_SNAP_ENCAPSULATION + +#include +#include "yans/callback.h" +#include "mac-address.h" +#include "packet.h" + +namespace yans { + +class MacNetworkInterface; + +class LlcSnapEncapsulation { +public: + typedef Callback RxCallback; + + uint32_t get_overhead (void) const; + void set_ipv4_callback (RxCallback callback); + void set_arp_callback (RxCallback callback); + void set_mac_interface (MacNetworkInterface *interface); + void send_ipv4 (Packet packet, MacAddress to); + void send_arp (Packet packet, MacAddress to); + void receive (Packet packet, MacNetworkInterface *interface); +private: + RxCallback m_ipv4_callback; + RxCallback m_arp_callback; + MacNetworkInterface *m_interface; +}; + +}; // namespace yans + +#endif /* LLC_SNAP_ENCAPSULATION */ diff --git a/src/common/mac-address-factory.cc b/src/common/mac-address-factory.cc new file mode 100644 index 000000000..3ba3c0287 --- /dev/null +++ b/src/common/mac-address-factory.cc @@ -0,0 +1,46 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "mac-address-factory.h" + +namespace yans { + +MacAddressFactory::MacAddressFactory () +{ + m_addr[0] = 0; + m_addr[1] = 0; + m_addr[2] = 0; + m_addr[3] = 0; + m_addr[4] = 0; + m_addr[5] = 0; + m_index = 0; +} + +MacAddress +MacAddressFactory::get_next (void) +{ + m_addr[m_index]++; + if (m_addr[m_index] == 0) { + m_index++; + } + return MacAddress (m_addr); +} + +}; // namespace yans diff --git a/src/common/mac-address-factory.h b/src/common/mac-address-factory.h new file mode 100644 index 000000000..dec330fb9 --- /dev/null +++ b/src/common/mac-address-factory.h @@ -0,0 +1,40 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef MAC_ADDRESS_FACTORY_H +#define MAC_ADDRESS_FACTORY_H + +#include "mac-address.h" + +namespace yans { + +class MacAddressFactory { +public: + MacAddressFactory (); + MacAddress get_next (void); +private: + uint8_t m_addr[6]; + uint8_t m_cur; + uint8_t m_index; +}; + +}; // namespace yans + +#endif /* MAC_ADDRESS_FACTORY_H */ diff --git a/src/common/mac-address.cc b/src/common/mac-address.cc new file mode 100644 index 000000000..635d853fe --- /dev/null +++ b/src/common/mac-address.cc @@ -0,0 +1,187 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "mac-address.h" +#include "utils.h" + +namespace yans { + +MacAddress::MacAddress () +{ + m_address[0] = 0; + m_address[1] = 0; + m_address[2] = 0; + m_address[3] = 0; + m_address[4] = 0; + m_address[5] = 0; +} + +MacAddress::MacAddress (uint8_t const address[6]) +{ + m_address[0] = address[0]; + m_address[1] = address[1]; + m_address[2] = address[2]; + m_address[3] = address[3]; + m_address[4] = address[4]; + m_address[5] = address[5]; +} +MacAddress::MacAddress (char const *address) +{ + ascii_to_mac_network (address, m_address); +} +MacAddress::MacAddress (uint32_t ip_multicast_address) +{ + m_address[0] = 1 | ((ip_multicast_address & 0x7f) << 1); + m_address[1] = (ip_multicast_address >> 7) & 0xff; + m_address[2] = (ip_multicast_address >> 16) & 0xff; + m_address[3] = 0x5e; + m_address[4] = 0; + m_address[5] = 0; +} +MacAddress::~MacAddress () +{} + +bool +MacAddress::is_equal (MacAddress other) const +{ + if (m_address[0] == other.m_address[0] && + m_address[1] == other.m_address[1] && + m_address[2] == other.m_address[2] && + m_address[3] == other.m_address[3] && + m_address[4] == other.m_address[4] && + m_address[5] == other.m_address[5]) { + return true; + } else { + return false; + } +} +bool +MacAddress::is_broadcast (void) const +{ + if (m_address[0] == 0xff && + m_address[1] == 0xff && + m_address[2] == 0xff && + m_address[3] == 0xff && + m_address[4] == 0xff && + m_address[5] == 0xff) { + return true; + } else { + return false; + } +} +bool +MacAddress::is_multicast (void) const +{ + if (m_address[0] & 0x1) { + return true; + } else { + return false; + } +} +bool +MacAddress::is_multicast_equal (MacAddress other) const +{ + if (get_multicast_part () == other.get_multicast_part ()) { + return true; + } else { + return false; + } +} + +uint32_t +MacAddress::get_multicast_part (void) const +{ + uint32_t part = 0; + part |= m_address[0] >> 1; + part |= m_address[1] << 7; + part |= (m_address[1] << 15); + return part; +} + + +void +MacAddress::peek (uint8_t ad[6]) const +{ + memcpy (ad, m_address, 6); +} +void +MacAddress::set (uint8_t const ad[6]) +{ + memcpy (m_address, ad, 6); +} + +void +MacAddress::print (std::ostream *os) const +{ + os->setf (std::ios::hex, std::ios::basefield); + *os << (uint32_t)m_address[0] << ":" + << (uint32_t)m_address[1] << ":" + << (uint32_t)m_address[2] << ":" + << (uint32_t)m_address[3] << ":" + << (uint32_t)m_address[4] << ":" + << (uint32_t)m_address[5]; + os->setf (std::ios::dec, std::ios::basefield); +} + + + + +MacAddress +MacAddress::get_broadcast (void) +{ + static MacAddress broadcast = MacAddress ("ff:ff:ff:ff:ff:ff"); + return broadcast; +} + +bool operator == (MacAddress const&a, MacAddress const&b) +{ + return a.is_equal (b); +} + +bool operator != (MacAddress const&a, MacAddress const&b) +{ + return !a.is_equal (b); +} + +bool operator < (MacAddress const&a, MacAddress const&b) +{ + uint8_t a_p[6]; + uint8_t b_p[6]; + a.peek (a_p); + b.peek (b_p); + for (uint8_t i = 0; i < 6; i++) { + if (a_p[i] < b_p[i]) { + return true; + } else if (a_p[i] > b_p[i]) { + return false; + } + } + return false; +} + +std::ostream& operator<< (std::ostream& os, MacAddress const& address) +{ + address.print (&os); + return os; +} + + +}; // namespace yans diff --git a/src/common/mac-address.h b/src/common/mac-address.h new file mode 100644 index 000000000..e1e240758 --- /dev/null +++ b/src/common/mac-address.h @@ -0,0 +1,72 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef MAC_ADDRESS_H +#define MAC_ADDRESS_H + +#include +#include + +namespace yans { + +class MacAddress { +public: + MacAddress (void); + /* low byte should be first. + */ + MacAddress (uint8_t const address[6]); + /* The string should look like this: + * hh-xx-xx-xx-xx-ll + * where hh is the high byte and ll is + * the low byte. + */ + MacAddress (char const *address); + /* create the mac address associated to + * this multicast ip address. + */ + MacAddress (uint32_t multicast_ip_address); + ~MacAddress (); + + bool is_equal (MacAddress other) const; + bool is_broadcast (void) const; + bool is_multicast (void) const; + bool is_multicast_equal (MacAddress other) const; + + void print (std::ostream *os) const; + + void peek (uint8_t ad[6]) const; + void set (uint8_t const ad[6]); + + static MacAddress get_broadcast (void); +private: + uint32_t get_multicast_part (void) const; + uint8_t m_address[6]; +}; + +bool operator == (MacAddress const&a, MacAddress const&b); +bool operator != (MacAddress const&a, MacAddress const&b); +bool operator < (MacAddress const&a, MacAddress const&b); + +std::ostream& operator<< (std::ostream& os, MacAddress const& address); + +}; // namespace yans + +#endif /* MAC_ADDRESS_H */ diff --git a/src/common/mac-network-interface.cc b/src/common/mac-network-interface.cc new file mode 100644 index 000000000..164aa2e73 --- /dev/null +++ b/src/common/mac-network-interface.cc @@ -0,0 +1,96 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "mac-network-interface.h" + +namespace yans { + +MacNetworkInterface::MacNetworkInterface (MacAddress self, uint16_t max_mtu) + : m_self (self), m_max_mtu (max_mtu), m_mtu (max_mtu) +{} +MacNetworkInterface::~MacNetworkInterface () +{} + +MacAddress +MacNetworkInterface::get_mac_address (void) const +{ + return m_self; +} +void +MacNetworkInterface::set_mtu (uint16_t mtu) +{ + if (mtu > m_max_mtu ) { + m_mtu = m_max_mtu; + } else { + m_mtu = mtu; + } +} +uint16_t +MacNetworkInterface::get_mtu (void) const +{ + return m_mtu; +} +bool +MacNetworkInterface::is_down (void) const +{ + return m_is_down; +} +void +MacNetworkInterface::set_up (void) +{ + m_is_down = false; + notify_up (); +} +void +MacNetworkInterface::set_down (void) +{ + m_is_down = true; + notify_down (); +} + +void +MacNetworkInterface::set_status_change_callback (StatusChangeCallback callback) +{ + m_status_change_callback = callback; +} + +void +MacNetworkInterface::set_rx_callback (RxCallback callback) +{ + m_rx_callback = callback; +} +void +MacNetworkInterface::send (Packet packet, MacAddress to) +{ + real_send (packet, to); +} +void +MacNetworkInterface::forward_up (Packet packet) +{ + m_rx_callback (packet, this); +} + +void +MacNetworkInterface::notify_status_change (void) +{ + m_status_change_callback (this); +} + +}; // namespace yans diff --git a/src/common/mac-network-interface.h b/src/common/mac-network-interface.h new file mode 100644 index 000000000..4218e955f --- /dev/null +++ b/src/common/mac-network-interface.h @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef MAC_NETWORK_INTERFACE_H +#define MAC_NETWORK_INTERFACE_H + +#include +#include "yans/callback.h" +#include "mac-address.h" +#include "packet.h" + +namespace yans { + +class MacNetworkInterface { +public: + typedef Callback RxCallback; + typedef Callback StatusChangeCallback; + + MacNetworkInterface (MacAddress self, uint16_t max_mtu); + virtual ~MacNetworkInterface () = 0; + + MacAddress get_mac_address (void) const; + void set_mtu (uint16_t mtu); + uint16_t get_mtu (void) const; + + bool is_down (void) const; + void set_up (void); + void set_down (void); + + void set_status_change_callback (StatusChangeCallback callback); + void set_rx_callback (RxCallback callback); + void send (Packet packet, MacAddress to); +protected: + void forward_up (Packet packet); + void notify_status_change (void); +private: + virtual void notify_up (void) = 0; + virtual void notify_down (void) = 0; + virtual void real_send (Packet packet, MacAddress to) = 0; + + StatusChangeCallback m_status_change_callback; + RxCallback m_rx_callback; + MacAddress m_self; + uint16_t m_max_mtu; + uint16_t m_mtu; + bool m_is_down; +}; + +}; // namespace yans + +#endif /* MAC_NETWORK_INTERFACE_H */ diff --git a/src/common/packet-logger.cc b/src/common/packet-logger.cc new file mode 100644 index 000000000..f70f545ed --- /dev/null +++ b/src/common/packet-logger.cc @@ -0,0 +1,42 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "packet-logger.h" + +namespace yans { + +PacketLogger::PacketLogger () +{} +void +PacketLogger::log (Packet const packet) +{ + if (!m_callback.is_null ()) { + m_callback (packet); + } +} +void +PacketLogger::set_callback (PacketLoggerCallback callback) +{ + m_callback = callback; +} + +}; // namespace yans + diff --git a/src/common/packet-logger.h b/src/common/packet-logger.h new file mode 100644 index 000000000..d414acf1e --- /dev/null +++ b/src/common/packet-logger.h @@ -0,0 +1,53 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef PACKET_LOGGER_H +#define PACKET_LOGGER_H + +#include "yans/callback.h" +#include "packet.h" + +namespace yans { + +/** + * \brief log packets + */ +class PacketLogger { +public: + typedef Callback PacketLoggerCallback; + PacketLogger (); + /** + * \param packet to log + * If a non-null callback was set, the packet + * is forwarded to that callback. + */ + void log (Packet const packet); + /** + * \param callback callback to store + */ + void set_callback (PacketLoggerCallback callback); +private: + PacketLoggerCallback m_callback; +}; + +}; // namespace yans + +#endif /* PACKET_LOGGER_H */ diff --git a/src/common/packet.cc b/src/common/packet.cc new file mode 100644 index 000000000..91d81d8a3 --- /dev/null +++ b/src/common/packet.cc @@ -0,0 +1,127 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "packet.h" +#include + +namespace yans { + +Packet::Packet () + : m_buffer () {} + +Packet::Packet (uint32_t size) + : m_buffer (size) +{} +Packet::Packet (Buffer buffer, Tags tags) + : m_buffer (buffer), + m_tags (tags) +{} + + +Packet +Packet::create_fragment (uint32_t start, uint32_t length) const +{ + Buffer tmp = m_buffer.create_fragment (start, length); + return Packet (tmp, m_tags); +} + +uint32_t +Packet::get_size (void) const +{ + return m_buffer.get_size (); +} + +void +Packet::add (Chunk *chunk) +{ + chunk->add (&m_buffer); +} + +void +Packet::peek (Chunk *chunk) const +{ + chunk->peek (&m_buffer); +} + +void +Packet::remove (Chunk *chunk) +{ + chunk->remove (&m_buffer); +} + + +void +Packet::write (PacketReadWriteCallback callback) const +{ + uint8_t *data = m_buffer.peek_data (); + uint32_t to_write = get_size (); + callback (data, to_write); +} + + +void +Packet::add_at_end (Packet packet) +{ + Buffer src = packet.m_buffer; + m_buffer.add_at_end (src.get_size ()); + Buffer::Iterator dest_start = m_buffer.end (); + dest_start.prev (src.get_size ()); + dest_start.write (src.begin (), src.end ()); + /** + * XXX: we might need to merge the tag list of the + * other packet into the current packet. + */ +} +void +Packet::add_at_end (Packet packet, uint32_t start, uint32_t size) +{ + assert (packet.get_size () <= start + size); + Buffer src = packet.m_buffer; + m_buffer.add_at_end (src.get_size ()); + Buffer::Iterator dest_start = m_buffer.end (); + dest_start.prev (size); + Buffer::Iterator src_start = src.begin (); + src_start.next (start); + Buffer::Iterator src_end = src_start; + src_end.next (size); + dest_start.write (src_start, src_end); + /** + * XXX: we might need to merge the tag list of the + * other packet into the current packet. + */ +} +void +Packet::remove_at_end (uint32_t size) +{ + m_buffer.remove_at_end (size); +} +void +Packet::remove_at_start (uint32_t size) +{ + m_buffer.remove_at_start (size); +} + +void +Packet::remove_all_tags (void) +{ + m_tags.remove_all (); +} + +}; // namespace yans diff --git a/src/common/packet.h b/src/common/packet.h new file mode 100644 index 000000000..04f4288c3 --- /dev/null +++ b/src/common/packet.h @@ -0,0 +1,90 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef PACKET_H +#define PACKET_H + +#include +#include "buffer.h" +#include "chunk.h" +#include "tags.h" +#include "yans/callback.h" + +namespace yans { + +class Packet { +public: + typedef Callback PacketReadWriteCallback; + Packet (); + Packet (uint32_t size); + Packet create_fragment (uint32_t start, uint32_t length) const; + uint32_t get_size (void) const; + void add (Chunk *chunk); + void peek (Chunk *chunk) const; + void remove (Chunk *chunk); + template + void add_tag (T const *tag); + template + bool remove_tag (T *tag); + template + bool peek_tag (T *tag) const; + template + bool update_tag (T const*tag); + void remove_all_tags (void); + void write (PacketReadWriteCallback callback) const; + void add_at_end (Packet packet); + void add_at_end (Packet packet, uint32_t offset, uint32_t size); + void remove_at_end (uint32_t size); + void remove_at_start (uint32_t size); + +private: + Packet (Buffer buffer, Tags tags); + Buffer m_buffer; + Tags m_tags; +}; + +}; // namespace yans + +namespace yans { + +template +void Packet::add_tag (T const*tag) +{ + m_tags.add (tag); +} +template +bool Packet::remove_tag (T *tag) +{ + return m_tags.remove (tag); +} +template +bool Packet::peek_tag (T *tag) const +{ + return m_tags.peek (tag); +} +template +bool Packet::update_tag (T const*tag) +{ + return m_tags.update (tag); +} + +}; // namespace yans + +#endif /* PACKET_H */ diff --git a/src/common/pcap-writer.cc b/src/common/pcap-writer.cc new file mode 100644 index 000000000..e9c980ef5 --- /dev/null +++ b/src/common/pcap-writer.cc @@ -0,0 +1,99 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +/* + * Documentation kindly pointed out by Tom Henderson: + * http://wiki.ethereal.com/Development/LibpcapFileFormat + */ + +#include "yans/simulator.h" +#include "yans/system-file.h" +#include "pcap-writer.h" +#include "packet.h" + + +namespace yans { + +enum { + PCAP_ETHERNET = 1 +}; + +PcapWriter::PcapWriter () +{ + m_writer = 0; + m_write_callback = make_callback (&PcapWriter::write_data, this); +} +PcapWriter::~PcapWriter () +{ + delete m_writer; +} + +void +PcapWriter::open (char const *name) +{ + m_writer = new SystemFile (); + m_writer->open (name); +} + +void +PcapWriter::write_header_ethernet (void) +{ + write_32 (0xa1b2c3d4); + write_16 (2); + write_16 (4); + write_32 (0); + write_32 (0); + write_32 (0xffff); + write_32 (PCAP_ETHERNET); +} + +void +PcapWriter::write_packet (Packet const packet) +{ + if (m_writer != 0) { + uint64_t current = Simulator::now_us (); + uint64_t s = current / 1000000; + uint64_t us = current % 1000000; + write_32 (s & 0xffffffff); + write_32 (us & 0xffffffff); + write_32 (packet.get_size ()); + write_32 (packet.get_size ()); + packet.write (m_write_callback); + } +} + +void +PcapWriter::write_data (uint8_t *buffer, uint32_t size) +{ + m_writer->write (buffer, size); +} +void +PcapWriter::write_32 (uint32_t data) +{ + m_writer->write ((uint8_t*)&data, 4); +} +void +PcapWriter::write_16 (uint16_t data) +{ + m_writer->write ((uint8_t*)&data, 2); +} + +}; // namespace yans diff --git a/src/common/pcap-writer.h b/src/common/pcap-writer.h new file mode 100644 index 000000000..1eca0da0c --- /dev/null +++ b/src/common/pcap-writer.h @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef PCAP_WRITER_H +#define PCAP_WRITER_H + +#include "yans/callback.h" +#include +#include "packet.h" + +namespace yans { + +class SystemFile; + +/** + * \brief Pcap output for Packet logger + * + * Log Packets to a file in pcap format which can be + * read by pcap readers. + */ +class PcapWriter { +public: + PcapWriter (); + ~PcapWriter (); + + /** + * \param name the name of the file to store packet log into. + * This method creates the file if it does not exist. If it + * exists, the file is emptied. + */ + void open (char const *name); + + /** + * Write a pcap header in the output file which specifies + * that the content of the file will Packets with + * Ethernet/LLC/SNAP encapsulation. + */ + void write_header_ethernet (void); + + /** + * \param packet packet to write to output file + */ + void write_packet (Packet const packet); + +private: + void write_data (uint8_t *buffer, uint32_t size); + void write_32 (uint32_t data); + void write_16 (uint16_t data); + SystemFile *m_writer; + Callback m_write_callback; +}; + +}; // namespace yans + +#endif /* PCAP_WRITER_H */ diff --git a/src/common/population-analysis.cc b/src/common/population-analysis.cc new file mode 100644 index 000000000..5853a0965 --- /dev/null +++ b/src/common/population-analysis.cc @@ -0,0 +1,94 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include +#include + +#include "population-analysis.h" + +/* This code is a C++ translation of Java code released under the GPLv2 + copyright Mathieu Lacage in treegrowth-stable: + http://cutebugs.net/code/treegrowth-stable. + */ + +namespace yans { + +PopulationAnalysis::PopulationAnalysis () +{ + reset (); +} +PopulationAnalysis::~PopulationAnalysis () +{} + +void +PopulationAnalysis::reset (void) +{ + m_n = 0; + m_square_sum = 0.0; + m_mean = 0.0; + m_sum = 0.0; +} + +void +PopulationAnalysis::add_term (double term) +{ + double d = (term - m_mean); + m_n++; + m_mean += d / m_n; + m_square_sum += d * (term - m_mean); + m_sum += term; +} + +uint32_t +PopulationAnalysis::get_n (void) +{ + return m_n; +} +double +PopulationAnalysis::get_total (void) +{ + return m_sum; +} +double +PopulationAnalysis::get_mean (void) +{ + return m_mean; +} +double +PopulationAnalysis::get_standard_deviation (void) +{ + if (m_n == 0) { + return 0.0; + } + assert (get_unbiased_variance () >= 0); + double deviation = sqrt (get_unbiased_variance ()); + return deviation; +} +double +PopulationAnalysis::get_unbiased_variance (void) +{ + if (m_n == 1 || m_n == 0) { + return 0.0; + } + return m_square_sum / (m_n - 1); +} + +}; // namespace yans diff --git a/src/common/population-analysis.h b/src/common/population-analysis.h new file mode 100644 index 000000000..7d8448a72 --- /dev/null +++ b/src/common/population-analysis.h @@ -0,0 +1,55 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + + +#ifndef POPULATION_ANALYSIS_H +#define POPULATION_ANALYSIS_H + +#include + +namespace yans { + +class PopulationAnalysis { +public: + PopulationAnalysis (); + ~PopulationAnalysis (); + + void reset (void); + + void add_term (double term); + + uint32_t get_n (void); + double get_total (void); + double get_mean (void); + double get_standard_deviation (void); + double get_unbiased_variance (void); + +private: + double m_mean; + double m_square_sum; + double m_sum; + uint32_t m_n; +}; + +}; // namespace yans + + +#endif /* POPULATION_ANALYSIS_H */ diff --git a/src/common/position.cc b/src/common/position.cc new file mode 100644 index 000000000..b7d5fcea6 --- /dev/null +++ b/src/common/position.cc @@ -0,0 +1,47 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "position.h" +#include + +namespace yans { + +Position::~Position () +{} + +void +Position::get (double &x, double &y, double &z) const +{ + real_get (x,y,z); +} +double +Position::get_distance_from (Position const*position) const +{ + double ox,oy,oz; + double x,y,z; + position->real_get (ox,oy,oz); + real_get (x,y,z); + double dx = ox - x; + double dy = oy - y; + double dz = oz - z; + return sqrt (dx*dx+dy*dy+dz*dz); +} + +}; // namespace yans diff --git a/src/common/position.h b/src/common/position.h new file mode 100644 index 000000000..a56aa4df5 --- /dev/null +++ b/src/common/position.h @@ -0,0 +1,38 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef POSITION_H +#define POSITION_H + +namespace yans { + +class Position { +public: + virtual ~Position () = 0; + + void get (double &x, double &y, double &z) const; + double get_distance_from (Position const*position) const; +private: + virtual void real_get (double &x, double &y, double &z) const = 0; +}; + +}; // namespace yans + +#endif /* POSITION_H */ diff --git a/src/common/random-uniform-mrg32k3a.cc b/src/common/random-uniform-mrg32k3a.cc new file mode 100644 index 000000000..4553cba36 --- /dev/null +++ b/src/common/random-uniform-mrg32k3a.cc @@ -0,0 +1,137 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "random-uniform.h" +#include "seed-generator.h" +#include "rng-mrg32k3a.h" + +namespace yans { + +class RandomUniformPrivate { +public: + RandomUniformPrivate (); + ~RandomUniformPrivate (); + + void reset (uint32_t seed); + + uint32_t get_max (void) const; + uint32_t get_min (void) const; + + uint32_t get_uint (void); + uint32_t get_uint (uint32_t n); + uint32_t get_uint (uint32_t a, uint32_t b); + double get_double (void); +private: + RngMrg32k3a m_rng; +}; + +RandomUniformPrivate::RandomUniformPrivate () + : m_rng () +{ + m_rng.reset (SeedGenerator::get ()); +} +RandomUniformPrivate::~RandomUniformPrivate () +{} + +void +RandomUniformPrivate::reset (uint32_t seed) +{ + m_rng.reset (seed); +} +uint32_t +RandomUniformPrivate::get_max (void) const +{ + return m_rng.get_max (); +} +uint32_t +RandomUniformPrivate::get_min (void) const +{ + return m_rng.get_min (); +} +uint32_t +RandomUniformPrivate::get_uint (void) +{ + return m_rng.get_uint (); +} +uint32_t +RandomUniformPrivate::get_uint (uint32_t n) +{ + return m_rng.get_uint (n); +} +uint32_t +RandomUniformPrivate::get_uint (uint32_t a, uint32_t b) +{ + return m_rng.get_uint (a, b); +} +double +RandomUniformPrivate::get_double (void) +{ + return m_rng.get_double (); +} + + + +RandomUniform::RandomUniform () + : m_priv (new RandomUniformPrivate ()) +{} +RandomUniform::~RandomUniform () +{ + delete m_priv; + m_priv = reinterpret_cast (0xdeadbeaf); +} + +void +RandomUniform::reset (uint32_t seed) +{ + m_priv->reset (seed); +} +uint32_t +RandomUniform::get_max (void) const +{ + return m_priv->get_max (); +} +uint32_t +RandomUniform::get_min (void) const +{ + return m_priv->get_min (); +} +uint32_t +RandomUniform::get_uint (void) +{ + return m_priv->get_uint (); +} +uint32_t +RandomUniform::get_uint (uint32_t n) +{ + return m_priv->get_uint (n); +} +uint32_t +RandomUniform::get_uint (uint32_t a, uint32_t b) +{ + return m_priv->get_uint (a, b); +} +double +RandomUniform::get_double (void) +{ + return m_priv->get_double (); +} + +}; // namespace yans + diff --git a/src/common/random-uniform.h b/src/common/random-uniform.h new file mode 100644 index 000000000..dc7233aeb --- /dev/null +++ b/src/common/random-uniform.h @@ -0,0 +1,57 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef RANDOM_UNIFORM_H +#define RANDOM_UNIFORM_H + +#include + +namespace yans { + +class RandomUniformPrivate; + +class RandomUniform { +public: + RandomUniform (); + ~RandomUniform (); + + void reset (uint32_t seed); + + uint32_t get_max (void) const; + uint32_t get_min (void) const; + + /* return an integer in the range [min,max] */ + uint32_t get_uint (void); + /* return an integer in the range [0,n] */ + uint32_t get_uint (uint32_t n); + /* return an integer in the range [a,b] */ + uint32_t get_uint (uint32_t a, uint32_t b); + /* return a floating-point number in the + * range [0,1) + */ + double get_double (void); +private: + RandomUniformPrivate *m_priv; +}; + +}; // namespace yans + + +#endif /* RANDOM_UNIFORM_H */ diff --git a/src/common/ref-ptr.h b/src/common/ref-ptr.h new file mode 100644 index 000000000..bcfc82b36 --- /dev/null +++ b/src/common/ref-ptr.h @@ -0,0 +1,139 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef REF_PTR_H +#define REF_PTR_H + +namespace yans { + +template +class RefPtr { +private: + T *m_env; +public: + RefPtr () + : m_env (0) + {} + + RefPtr (T *env) + : m_env (env) + {} + RefPtr (RefPtr const&o) + : m_env (o.m_env) + { + if (m_env != 0) { + m_env->m_count++; + } + } + // allow conversions from T to T const. + template + RefPtr (RefPtr const &o) + : m_env (o.peek ()) + { + if (m_env != 0) { + m_env->m_count++; + } + } + ~RefPtr () + { + if (m_env != 0) { + m_env->m_count--; + if (m_env->m_count == 0) { + m_env->destroy (); + } + } + } + RefPtr &operator = (RefPtr const& o) + { + if (o.m_env != 0) { + o.m_env->m_count++; + } + if (m_env != 0) { + m_env->m_count--; + if (m_env->m_count == 0) { + m_env->destroy (); + } + } + m_env = o.m_env; + return *this; + } + T *operator -> () + { + return m_env; + } + T *operator -> () const + { + return m_env; + } + // allow if (!sp) + bool operator! () + { + return m_env == 0; + } +private: + class Tester { + private: + void operator delete (void *); + }; +public: + // allow if (sp) + operator Tester * () const + { + if (m_env == 0) { + return 0; + } + static Tester test; + return &test; + } + // allow if (sp == 0) + inline friend bool operator == (RefPtr const &lhs, T const *rhs) + { + return lhs.m_env == rhs; + } + // allow if (0 == sp) + inline friend bool operator == (T const *lhs, RefPtr &rhs) + { + return lhs == rhs.m_env; + } + // allow if (sp != 0) + inline friend bool operator != (RefPtr const &lhs, T const *rhs) + { + return lhs.m_env != rhs; + } + // allow if (0 != sp) + inline friend bool operator != (T const *lhs, RefPtr &rhs) + { + return lhs != rhs.m_env; + } + + T *peek (void) + { + return m_env; + } + T *peek (void) const + { + return m_env; + } +}; + +}; // namespace yans + +#endif /* REF_PTR_H */ diff --git a/src/common/rng-mrg32k3a.cc b/src/common/rng-mrg32k3a.cc new file mode 100644 index 000000000..cb21f31e9 --- /dev/null +++ b/src/common/rng-mrg32k3a.cc @@ -0,0 +1,336 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (C) 2001 Pierre L'Ecuyer (lecuyer@iro.umontreal.ca) + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include "rng-mrg32k3a.h" +#include "seed-generator.h" +#include + +#ifndef MAXINT +#define MAXINT 2147483647 // XX [for now] +#endif + + +using namespace std; +namespace +{ + const double m1 = 4294967087.0; + const double m2 = 4294944443.0; + const double norm = 1.0 / (m1 + 1.0); + const double a12 = 1403580.0; + const double a13n = 810728.0; + const double a21 = 527612.0; + const double a23n = 1370589.0; + const double two17 = 131072.0; + const double two53 = 9007199254740992.0; + const double fact = 5.9604644775390625e-8; /* 1 / 2^24 */ + + // The following are the transition matrices of the two MRG + // components (in matrix form), raised to the powers -1, 1, + // 2^76, and 2^127, resp. + + const double InvA1[3][3] = { // Inverse of A1p0 + { 184888585.0, 0.0, 1945170933.0 }, + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 } + }; + + const double InvA2[3][3] = { // Inverse of A2p0 + { 0.0, 360363334.0, 4225571728.0 }, + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 } + }; + + const double A1p0[3][3] = { + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { -810728.0, 1403580.0, 0.0 } + }; + + const double A2p0[3][3] = { + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { -1370589.0, 0.0, 527612.0 } + }; + + const double A1p76[3][3] = { + { 82758667.0, 1871391091.0, 4127413238.0 }, + { 3672831523.0, 69195019.0, 1871391091.0 }, + { 3672091415.0, 3528743235.0, 69195019.0 } + }; + + const double A2p76[3][3] = { + { 1511326704.0, 3759209742.0, 1610795712.0 }, + { 4292754251.0, 1511326704.0, 3889917532.0 }, + { 3859662829.0, 4292754251.0, 3708466080.0 } + }; + + const double A1p127[3][3] = { + { 2427906178.0, 3580155704.0, 949770784.0 }, + { 226153695.0, 1230515664.0, 3580155704.0 }, + { 1988835001.0, 986791581.0, 1230515664.0 } + }; + + const double A2p127[3][3] = { + { 1464411153.0, 277697599.0, 1610723613.0 }, + { 32183930.0, 1464411153.0, 1022607788.0 }, + { 2824425944.0, 32183930.0, 2093834863.0 } + }; + +} // end of anonymous namespace + +//------------------------------------------------------------------- +// Return (a*s + c) MOD m; a, s, c and m must be < 2^35 +// + +double +RngMrg32k3a::MultModM (double a, double s, double c, double m) +{ + double v; + long a1; + v=a*s+c; + + if (v >= two53 || v <= -two53) { + a1 = static_cast (a / two17); a -= a1 * two17; + v =a1*s; + a1 = static_cast (v / m); v -= a1 * m; + v = v * two17 + a * s + c; + } + a1 = static_cast (v / m); + /* in case v < 0)*/ + if ((v -= a1 * m) < 0.0) return v += m; else return v; +} + +//------------------------------------------------------------------- +// Compute the vector v = A*s MOD m. Assume that -m < s[i] < m. +// Works also when v = s. +// +void +RngMrg32k3a::MatVecModM (const double A[3][3], const double s[3], double v[3], + double m) +{ + int i; + double x[3]; // Necessary if v = s + for (i = 0; i < 3; ++i) { + x[i] = MultModM (A[i][0], s[0], 0.0, m); + x[i] = MultModM (A[i][1], s[1], x[i], m); + x[i] = MultModM (A[i][2], s[2], x[i], m); + } + for (i = 0; i < 3; ++i) + v[i] = x[i]; +} + +//------------------------------------------------------------------- +// Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m. +// Note: works also if A = C or B = C or A = B = C. +// +void +RngMrg32k3a::MatMatModM (const double A[3][3], const double B[3][3], + double C[3][3], double m) +{ + int i, j; + double V[3], W[3][3]; + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) + V[j] = B[j][i]; + MatVecModM (A, V, V, m); + for (j = 0; j < 3; ++j) + + W[j][i] = V[j]; + } + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) + C[i][j] = W[i][j]; +} + +//------------------------------------------------------------------- +// Compute the matrix B = (A^(2^e) Mod m); works also if A = B. +// +void +RngMrg32k3a::MatTwoPowModM (const double A[3][3], double B[3][3], double m, + long e) +{ + int i, j; + /* initialize: B = A */ + if (A != B) { + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) + B[i][j] = A[i][j]; + } + /* Compute B = A^(2^e) mod m */ + for (i = 0; i < e; i++) + MatMatModM (B, B, B, m); +} + +//------------------------------------------------------------------- +// Compute the matrix B = (A^n Mod m); works even if A = B. +// +void +RngMrg32k3a::MatPowModM (const double A[3][3], double B[3][3], double m, + long n) +{ + int i, j; + double W[3][3]; + /* initialize: W = A; B = I */ + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) { + W[i][j] = A[i][j]; + B[i][j] = 0.0; + } + for (j = 0; j < 3; ++j) + B[j][j] = 1.0; + /* Compute B = A^n mod m using the binary decomposition of n */ + while (n > 0) { + if (n % 2) MatMatModM (W, B, B, m); + MatMatModM (W, W, W, m); + + n/=2; + } +} + +//-------------------------------------------------------------------- +// Check that the seeds are legitimate values. Returns 0 if legal +// seeds, -1 otherwise. +// +int +RngMrg32k3a::CheckSeed (const unsigned long seed[6]) +{ + int i; + for (i = 0; i < 3; ++i) { + if (seed[i] >= m1) { + std::cerr << "****************************************" << std::endl + << "ERROR: Seed["<= 4294967087, Seed is not set." << std::endl + << "****************************************" << std::endl; + return (-1); + } + } + for (i = 3; i < 6; ++i) { + if (seed[i] >= m2) { + std::cerr << "****************************************" << std::endl + << "ERROR: Seed["<= 429444443, Seed is not set."< (p1 / m1); + p1 -= k * m1; + if (p1 < 0.0) p1 += m1; + Cg_[0] = Cg_[1]; Cg_[1] = Cg_[2]; Cg_[2] = p1; + /* Component 2 */ + p2 = a21 * Cg_[5] - a23n * Cg_[3]; + k = static_cast (p2 / m2); + p2 -= k * m2; + if (p2 < 0.0) p2 += m2; + Cg_[3] = Cg_[4]; Cg_[4] = Cg_[5]; Cg_[5] = p2; + /* Combination */ + u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm); + return u; +} + +//------------------------------------------------------------------------- +// Generate the next random number with extended (53 bits) precision. +// +double RngMrg32k3a::U01d () +{ + double u; + u = U01(); + u += (U01() - 1.0) * fact; + return (u < 0.0) ? u + 1.0 : u; +} + +//************************************************************************* +// Public members of the class start here +//------------------------------------------------------------------------- + +RngMrg32k3a::RngMrg32k3a () +{} + +void RngMrg32k3a::reset (long seed) +{ + for (int i = 0; i < 6; ++i) { + Bg_[i] = Cg_[i] = Ig_[i] = seed; + } +} + + +//------------------------------------------------------------------------- +// Generate the next random number. +// + +uint32_t +RngMrg32k3a::get_max (void) const +{ + return MAXINT; +} +uint32_t +RngMrg32k3a::get_min (void) const +{ + return 0; +} + +uint32_t +RngMrg32k3a::get_uint (void) +{ + return get_uint (0, MAXINT); +} + +uint32_t +RngMrg32k3a::get_uint (uint32_t n) +{ + return get_uint (0, n); +} + +uint32_t +RngMrg32k3a::get_uint (uint32_t low, uint32_t high) +{ + return ((uint32_t) (low + (uint32_t) (((uint32_t) + (high-low+1)) * U01()))); +} + +double +RngMrg32k3a::get_double (void) +{ + + return U01d (); +} diff --git a/src/common/rng-mrg32k3a.h b/src/common/rng-mrg32k3a.h new file mode 100644 index 000000000..a1b695bcc --- /dev/null +++ b/src/common/rng-mrg32k3a.h @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (C) 2001 Pierre L'Ecuyer (lecuyer@iro.umontreal.ca) + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef RNG_MRG32k3A_H +#define RNG_MRG32k3A_H + +#include + + +/* + * Use class RNG in real programs. + */ +class RngMrg32k3a { +public: + RngMrg32k3a (); + + void reset (long seed); + + + uint32_t get_max (void) const; + uint32_t get_min (void) const; + uint32_t get_uint (void); + uint32_t get_uint (uint32_t n); + uint32_t get_uint (uint32_t low, uint32_t high); + double get_double (void); + +private: + double U01 (); + double U01d (); + double MultModM (double a, double s, double c, double m); + void MatVecModM (const double A[3][3], const double s[3], double v[3], + double m); + void MatMatModM (const double A[3][3], const double B[3][3], + double C[3][3], double m) ; + void MatTwoPowModM (const double A[3][3], double B[3][3], double m, + long e); + void MatPowModM (const double A[3][3], double B[3][3], double m, + long n); + int CheckSeed (const unsigned long seed[6]); + + /* + Vectors to store the current seed, the beginning of the current block + (substream) and the beginning of the current stream. + */ + double Cg_[6], Bg_[6], Ig_[6]; +}; + +#endif /* RNG_MRG32k3A_H */ diff --git a/src/common/seed-generator-mrg32k3a.cc b/src/common/seed-generator-mrg32k3a.cc new file mode 100644 index 000000000..d92527cb0 --- /dev/null +++ b/src/common/seed-generator-mrg32k3a.cc @@ -0,0 +1,61 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "seed-generator.h" +#include "rng-mrg32k3a.h" + +namespace yans { + +class SeedGeneratorPrivate { +public: + static void destroy (void); + static void reset (uint32_t seed); + static uint32_t get (void); +private: + static RngMrg32k3a m_generator; +}; + +RngMrg32k3a SeedGeneratorPrivate::m_generator; + +void +SeedGeneratorPrivate::reset (uint32_t seed) +{ + m_generator.reset (seed); +} +uint32_t +SeedGeneratorPrivate::get (void) +{ + return m_generator.get_uint (); +} + + + +void +SeedGenerator::reset (uint32_t seed) +{ + SeedGeneratorPrivate::reset (seed); +} +uint32_t +SeedGenerator::get (void) +{ + return SeedGeneratorPrivate::get (); +} + +}; // namespace yans diff --git a/src/common/seed-generator.h b/src/common/seed-generator.h new file mode 100644 index 000000000..fef5b61f2 --- /dev/null +++ b/src/common/seed-generator.h @@ -0,0 +1,40 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef SEED_GENERATOR_H +#define SEED_GENERATOR_H + +#include + +namespace yans { + +class SeedGeneratorPrivate; + +class SeedGenerator { +public: + static void reset (uint32_t seed); + static uint32_t get (void); +private: + SeedGenerator (); +}; + +}; // namespace yans + +#endif /* SEED_GENERATOR_H */ diff --git a/src/common/sgi-hashmap.h b/src/common/sgi-hashmap.h new file mode 100644 index 000000000..666e8cfe6 --- /dev/null +++ b/src/common/sgi-hashmap.h @@ -0,0 +1,32 @@ +/* This code snippet was ripped out of the gcc + * documentation and slightly modified to work + * with gcc 4.x + */ +#ifndef SGI_HASHMAP_H +#define SGI_HASHMAP_H + +/* To use gcc extensions. + */ +#ifdef __GNUC__ + #if __GNUC__ < 3 + #include +namespace Sgi { using ::hash_map; }; // inherit globals + #else + #if __GNUC__ < 4 + #include + #if __GNUC_MINOR__ == 0 +namespace Sgi = std; // GCC 3.0 + #else +namespace Sgi = ::__gnu_cxx; // GCC 3.1 and later + #endif + #else // gcc 4.x and later + #include + namespace Sgi = ::__gnu_cxx; + #endif + #endif +#else // ... there are other compilers, right? +namespace Sgi = std; +#endif + + +#endif /* SGI_HASHMAP_H */ diff --git a/src/common/si-traced-variable.tcc b/src/common/si-traced-variable.tcc new file mode 100644 index 000000000..ba7f4aea8 --- /dev/null +++ b/src/common/si-traced-variable.tcc @@ -0,0 +1,237 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SI_TRACED_VARIABLE_TCC +#define SI_TRACED_VARIABLE_TCC + +#include "yans/callback.h" +#include + +namespace yans { + +class SiTracedVariableBase { +public: + typedef Callback ChangeNotifyCallback; + + SiTracedVariableBase () {} + SiTracedVariableBase (SiTracedVariableBase const &o) {} + SiTracedVariableBase &operator = (SiTracedVariableBase const &o) { + return *this; + } + + ~SiTracedVariableBase () {} + + void set_callback(ChangeNotifyCallback callback) { + m_callback = callback; + } +protected: + void notify (int64_t old_val, int64_t new_val) { + if (old_val != new_val && !m_callback.is_null ()) { + m_callback (old_val, new_val); + } + } +private: + ChangeNotifyCallback m_callback; +}; + +template +class UiTracedVariable; + + +/** + * \brief trace variables of type "signed integer" + * + * This template class implements a POD type: it + * behaves like any other variable of type "signed integer" + * except that it also reports any changes to its + * value with its internal callback. + * + * To instantiate a 32-bit signed variable (to store + * a TCP counter for example), you would create a variable of type + * yans::UiTracedVariable : + \code + #include + #include "yans/si-traced-variable.tcc" + + yans::SiTracedVariable var; + \endcode + * and you would use it like any other variable of type int32_t: + \code + var += 12; + var = 10; + var = -10; + \endcode + */ +template +class SiTracedVariable : public SiTracedVariableBase { +public: + SiTracedVariable () + : m_var (0) + {} + SiTracedVariable (T const &var) + : m_var (var) + {} + + SiTracedVariable &operator = (SiTracedVariable const &o) { + assign (o.get ()); + return *this; + } + template + SiTracedVariable &operator = (SiTracedVariable const &o) { + assign (o.get ()); + return *this; + } + template + SiTracedVariable &operator = (UiTracedVariable const &o) { + assign (o.get ()); + return *this; + } + SiTracedVariable &operator++ () { + assign (get () + 1); + return *this; + } + SiTracedVariable &operator-- () { + assign (get () - 1); + return *this; + } + SiTracedVariable operator++ (int) { + SiTracedVariable old (*this); + ++*this; + return old; + } + SiTracedVariable operator-- (int) { + SiTracedVariable old (*this); + --*this; + return old; + } + operator T () const { + return get (); + } + + + void assign (T var) { + notify (m_var, var); + m_var = var; + } + T get (void) const { + return m_var; + } + +private: + T m_var; +}; + +template +SiTracedVariable &operator += (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () + rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator -= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () - rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator *= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () * rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator /= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () / rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator <<= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () << rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator >>= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () >> rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator &= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () & rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator |= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () | rhs.get ()); + return lhs; +} +template +SiTracedVariable &operator ^= (SiTracedVariable &lhs, SiTracedVariable const &rhs) { + lhs.assign (lhs.get () ^ rhs.get ()); + return lhs; +} + + +template +SiTracedVariable &operator += (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () + rhs); + return lhs; +} +template +SiTracedVariable &operator -= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () - rhs); + return lhs; +} +template +SiTracedVariable &operator *= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () * rhs); + return lhs; +} +template +SiTracedVariable &operator /= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () / rhs); + return lhs; +} +template +SiTracedVariable &operator <<= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () << rhs); + return lhs; +} +template +SiTracedVariable &operator >>= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () >> rhs); + return lhs; +} +template +SiTracedVariable &operator &= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () & rhs); + return lhs; +} +template +SiTracedVariable &operator |= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () | rhs); + return lhs; +} +template +SiTracedVariable &operator ^= (SiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () ^ rhs); + return lhs; +} + +}; // namespace yans + +#endif /* TRACED_VARIABLE_TCC */ diff --git a/src/common/static-position.cc b/src/common/static-position.cc new file mode 100644 index 000000000..c2b769690 --- /dev/null +++ b/src/common/static-position.cc @@ -0,0 +1,46 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "static-position.h" + +namespace yans { + +StaticPosition::StaticPosition () + : m_x (0.0), m_y (0.0), m_z (0.0) +{} +StaticPosition::~StaticPosition () +{} + +void +StaticPosition::set (double x, double y, double z) +{ + m_x = x; + m_y = y; + m_z = z; +} +void +StaticPosition::real_get (double &x, double &y, double &z) const +{ + x = m_x; + y = m_y; + z = m_z; +} + +}; // namespace yans diff --git a/src/common/static-position.h b/src/common/static-position.h new file mode 100644 index 000000000..c19debc8a --- /dev/null +++ b/src/common/static-position.h @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef STATIC_POSITION_H +#define STATIC_POSITION_H + +#include "position.h" + +namespace yans { + +class StaticPosition : public Position { +public: + StaticPosition (); + virtual ~StaticPosition (); + + void set (double x, double y, double z); +private: + virtual void real_get (double &x, double &y, double &z) const; + double m_x; + double m_y; + double m_z; +}; + +}; // namespace yans + +#endif /* STATIC_POSITION_H */ diff --git a/src/common/static-speed-position.cc b/src/common/static-speed-position.cc new file mode 100644 index 000000000..0953d8b43 --- /dev/null +++ b/src/common/static-speed-position.cc @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "static-speed-position.h" +#include "yans/simulator.h" + +namespace yans { + +StaticSpeedPosition::StaticSpeedPosition () + : m_x (0.0), + m_y (0.0), + m_z (0.0), + m_dx (0.0), + m_dy (0.0), + m_dz (0.0), + m_prev_us (0) +{} +StaticSpeedPosition::~StaticSpeedPosition () +{} + +void +StaticSpeedPosition::set (double x, double y, double z) +{ + m_x = x; + m_y = y; + m_z = z; +} + +void +StaticSpeedPosition::set_delta (double dx, double dy, double dz) +{ + m_dx = dx / 1000000; + m_dy = dy / 1000000; + m_dz = dz / 1000000; +} + +void +StaticSpeedPosition::real_get (double &x, double &y, double &z) const +{ + uint64_t now_us = Simulator::now_us (); + uint64_t delta_us = now_us - m_prev_us; + m_x += m_dx * delta_us; + m_y += m_dy * delta_us; + m_z += m_dz * delta_us; + m_prev_us = now_us; + x = m_x; + y = m_y; + z = m_z; +} + +}; // namespace yans diff --git a/src/common/static-speed-position.h b/src/common/static-speed-position.h new file mode 100644 index 000000000..2fa53f733 --- /dev/null +++ b/src/common/static-speed-position.h @@ -0,0 +1,51 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef STATIC_SPEED_POSITION_H +#define STATIC_SPEED_POSITION_H + +#include +#include "position.h" + +namespace yans { + +class StaticSpeedPosition : public Position { +public: + StaticSpeedPosition (); + virtual ~StaticSpeedPosition (); + + // m + void set (double x, double y, double z); + // m/s + void set_delta (double dx, double dy, double dz); +private: + virtual void real_get (double &x, double &y, double &z) const; + mutable double m_x; + mutable double m_y; + mutable double m_z; + double m_dx; + double m_dy; + double m_dz; + mutable uint64_t m_prev_us; +}; + +}; // namespace yans + +#endif /* STATIC_SPEED_POSITION */ diff --git a/src/common/tags.cc b/src/common/tags.cc new file mode 100644 index 000000000..297968599 --- /dev/null +++ b/src/common/tags.cc @@ -0,0 +1,322 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "tags.h" +#include + +namespace yans { + +TagsPrettyPrinterRegistry::PrettyPrinters TagsPrettyPrinterRegistry::g_pretty_printers; + +void +TagsPrettyPrinterRegistry::record (uint32_t uid, void (*cb) (uint8_t [Tags::SIZE], std::ostream &)) +{ + for (PrettyPrintersI i = g_pretty_printers.begin (); + i != g_pretty_printers.end (); i++) { + if (i->first == uid) { + i->second = cb; + return; + } + } + g_pretty_printers.push_back (std::make_pair (uid, cb)); +} +void +TagsPrettyPrinterRegistry::pretty_print (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os) +{ + for (PrettyPrintersI i = g_pretty_printers.begin (); + i != g_pretty_printers.end (); i++) { + if (i->first == uid) { + if (i->second == 0) { + os << "tag uid="<second)) (buf, os); + } + return; + } + } + os << "tag uid="<m_next; + g_n_free--; + } else { + retval = new struct Tags::TagData (); + } + return retval; +} + +void +Tags::free_data (struct TagData *data) +{ + if (g_n_free > 1000) { + delete data; + return; + } + g_n_free++; + data->m_next = g_free; + g_free = data; +} +#else +struct Tags::TagData * +Tags::alloc_data (void) +{ + struct Tags::TagData *retval; + retval = new struct Tags::TagData (); + return retval; +} + +void +Tags::free_data (struct TagData *data) +{ + delete data; +} +#endif + +bool +Tags::remove (uint32_t id) +{ + bool found = false; + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { + if (cur->m_id == id) { + found = true; + } + } + if (!found) { + return false; + } + struct TagData *start = 0; + struct TagData **prev_next = &start; + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { + if (cur->m_id == id) { + /** + * XXX + * Note: I believe that we could optimize this to + * avoid copying each TagData located after the target id + * and just link the already-copied list to the next tag. + */ + continue; + } + struct TagData *copy = alloc_data (); + copy->m_id = cur->m_id; + copy->m_count = 1; + copy->m_next = 0; + memcpy (copy->m_data, cur->m_data, Tags::SIZE); + *prev_next = copy; + prev_next = ©->m_next; + } + *prev_next = 0; + remove_all (); + m_next = start; + return true; +} + +bool +Tags::update (uint8_t const*buffer, uint32_t id) +{ + if (!remove (id)) { + return false; + } + struct TagData *new_start = alloc_data (); + new_start->m_count = 1; + new_start->m_next = 0; + new_start->m_id = id; + memcpy (new_start->m_data, buffer, Tags::SIZE); + new_start->m_next = m_next; + m_next = new_start; + return true; +} + +void +Tags::pretty_print (std::ostream &os) +{ + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { + TagsPrettyPrinterRegistry::pretty_print (cur->m_id, cur->m_data, os); + } +} + + +}; // namespace yans + +#ifdef RUN_SELF_TESTS + +#include "yans/test.h" +#include +#include + +namespace yans { + +class TagsTest : Test { +public: + TagsTest (); + virtual ~TagsTest (); + virtual bool run_tests (void); +}; + +struct my_tag_a { + uint8_t a; +}; +struct my_tag_b { + uint32_t b; +}; +struct my_tag_c { + uint8_t c [Tags::SIZE]; +}; +struct my_invalid_tag { + uint8_t invalid [Tags::SIZE+1]; +}; + +static void +my_tag_a_pretty_printer_cb (struct my_tag_a *a, std::ostream &os) +{ + os << "struct my_tag_a, a="<<(uint32_t)a->a< + */ +#ifndef TAGS_H +#define TAGS_H + +#include +#include +#include + +namespace yans { + +template +class TagPrettyPrinter; + +class Tags { +public: + inline Tags (); + inline Tags (Tags const &o); + inline Tags &operator = (Tags const &o); + inline ~Tags (); + + template + void add (T const*tag); + + template + bool remove (T *tag); + + template + bool peek (T *tag) const; + + template + bool update (T const*tag); + + void pretty_print (std::ostream &os); + + inline void remove_all (void); + + enum { + SIZE = 16 + }; +private: + struct TagData { + struct TagData *m_next; + uint32_t m_id; + uint32_t m_count; + uint8_t m_data[Tags::SIZE]; + }; + class UidFactory { + public: + static uint32_t create (void); + }; + + bool remove (uint32_t id); + bool update (uint8_t const*buffer, uint32_t id); + struct Tags::TagData *alloc_data (void); + void free_data (struct TagData *data); + + static struct Tags::TagData *g_free; + static uint32_t g_n_free; + + struct TagData *m_next; +}; + +/** + * This class is used to register a pretty-printer + * callback function to print in a nice user-friendly + * way the content of the target type. To register + * such a type, all you need to do is instantiate + * an instance of this type any number of times (at + * least once). Typical users will create static global + * variable of this type and construct it with + * the proper function pointer. + */ +template +class TagPrettyPrinter { +public: + TagPrettyPrinter (void(*) (T *, std::ostream &)); +private: + TagPrettyPrinter (); + static void pretty_print_cb (uint8_t *buf, std::ostream &os); + static void(*g_pretty_printer) (T *, std::ostream &); +}; + +class TagsPrettyPrinterRegistry { +public: + static void record (uint32_t uid, void (*cb) (uint8_t buf[Tags::SIZE], std::ostream &os)); + static void pretty_print (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os); +private: + typedef std::vector > PrettyPrinters; + typedef std::vector >::iterator PrettyPrintersI; + static PrettyPrinters g_pretty_printers; +}; + + +}; // namespace yans + + +#include +#include + +namespace yans { + +/** + * The TypeUid class is used to create a mapping Type --> uid + * Of course, this class is not perfect: the value of the uid + * associated to a given type could change accross multiple + * runs of the same program on the same platform or accross + * multiple platforms. There exist no generic portable + * workaround/solution to this problem also known as + * "type id management". The only other reliable solution + * is to ask programmers to assign themselves a uid to each + * type but this is painful from a management perspective. + * + * So, for now, this class is good enough provided you do + * not try to serialize to permanent storage the type uids + * generated by this class. Just don't try to do it. It might + * seem to work but it will fail spectacularily in certain + * use-cases and you will cry from debugging this. Hear me ? + */ +template +class TypeUid { +public: + static const uint32_t get_uid (void); +private: + T real_type; +}; + +template +const uint32_t TypeUid::get_uid (void) +{ + static const uint32_t uid = Tags::UidFactory::create (); + return uid; +} + + + +/** + * Implementation of the TagPrettyPrinter registration class. + * It records a callback with the TagPrettyPrinterRegistry. + * This callback performs type conversion before forwarding + * the call to the user-provided function. + */ +template +TagPrettyPrinter::TagPrettyPrinter (void(*pretty_printer) (T *, std::ostream &)) +{ + g_pretty_printer = pretty_printer; + TagsPrettyPrinterRegistry::record (TypeUid::get_uid (), + &TagPrettyPrinter::pretty_print_cb); +} +template +void +TagPrettyPrinter::pretty_print_cb (uint8_t buf[Tags::SIZE], std::ostream &os) +{ + assert (sizeof (T) <= Tags::SIZE); + T *tag = reinterpret_cast (buf); + (*g_pretty_printer) (tag, os); +} + +template +void (*TagPrettyPrinter::g_pretty_printer) (T *, std::ostream &) = 0; + + + + +template +void +Tags::add (T const*tag) +{ + assert (sizeof (T) <= Tags::SIZE); + uint8_t const*buf = reinterpret_cast (tag); + // ensure this id was not yet added + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { + assert (cur->m_id != TypeUid::get_uid ()); + } + struct TagData *new_start = alloc_data (); + new_start->m_count = 1; + new_start->m_next = 0; + new_start->m_id = TypeUid::get_uid (); + memcpy (new_start->m_data, buf, sizeof (T)); + new_start->m_next = m_next; + m_next = new_start; +} + +template +bool +Tags::remove (T *tag) +{ + assert (sizeof (T) <= Tags::SIZE); + return remove (TypeUid::get_uid ()); +} + +template +bool +Tags::peek (T *tag) const +{ + assert (sizeof (T) <= Tags::SIZE); + uint8_t *buf = reinterpret_cast (tag); + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { + if (cur->m_id == TypeUid::get_uid ()) { + /* found tag */ + memcpy (buf, cur->m_data, sizeof (T)); + return true; + } + } + /* no tag found */ + return false; +} + +template +bool +Tags::update (T const*tag) +{ + assert (sizeof (T) <= Tags::SIZE); + uint8_t const*buf = reinterpret_cast (tag); + return update (buf, TypeUid::get_uid ()); +} + + +Tags::Tags () + : m_next () +{} + +Tags::Tags (Tags const &o) + : m_next (o.m_next) +{ + if (m_next != 0) { + m_next->m_count++; + } +} + +Tags & +Tags::operator = (Tags const &o) +{ + // self assignment + if (m_next == o.m_next) { + return *this; + } + remove_all (); + m_next = o.m_next; + if (m_next != 0) { + m_next->m_count++; + } + return *this; +} + +Tags::~Tags () +{ + remove_all (); +} + +void +Tags::remove_all (void) +{ + struct TagData *prev = 0; + for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) { + cur->m_count--; + if (cur->m_count > 0) { + break; + } + if (prev != 0) { + free_data (prev); + } + prev = cur; + } + if (prev != 0) { + free_data (prev); + } + m_next = 0; +} + + +}; // namespace yans + +#endif /* TAGS_H */ diff --git a/src/common/timeout.cc b/src/common/timeout.cc new file mode 100644 index 000000000..ec78e5e09 --- /dev/null +++ b/src/common/timeout.cc @@ -0,0 +1,77 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "timeout.h" +#include "yans/simulator.h" +#include "yans/event.tcc" + +namespace yans { + +Timeout::Timeout (ExpireCallback callback) + : m_interval_us (0), + m_count (0), + m_current_count (0), + m_stop (false), + m_callback (callback) +{} +Timeout::~Timeout () +{} +void +Timeout::set_interval (uint64_t us) +{ + m_interval_us = us; +} +void +Timeout::set_count (uint32_t count) +{ + m_count = count; +} + + +void Timeout::start (void) +{ + Simulator::schedule_rel_us (m_interval_us, + make_event (&Timeout::expire, this)); +} +void Timeout::stop (void) +{ + m_stop = true; +} +void Timeout::restart (void) +{ + m_current_count = m_count; +} +void +Timeout::expire (void) +{ + if (m_stop) { + return; + } + m_current_count--; + if (m_current_count == 0) { + m_callback (); + return; + } + Simulator::schedule_rel_us (m_interval_us, + make_event (&Timeout::expire, this)); +} + + +}; // namespace yans diff --git a/src/common/timeout.h b/src/common/timeout.h new file mode 100644 index 000000000..cab3bc6b2 --- /dev/null +++ b/src/common/timeout.h @@ -0,0 +1,52 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef TIMEOUT_H +#define TIMEOUT_H + +#include +#include "yans/callback.h" + +namespace yans { + +class Timeout { +public: + typedef Callback ExpireCallback; + Timeout (ExpireCallback callback); + ~Timeout (); + void set_interval (uint64_t us); + void set_count (uint32_t count); + void start (void); + void stop (void); + void restart (void); +private: + Timeout (); + void expire (void); + uint64_t m_interval_us; + uint32_t m_count; + uint32_t m_current_count; + bool m_stop; + ExpireCallback m_callback; +}; + +}; // namespace yans + +#endif /* TIMEOUT_H */ diff --git a/src/common/trace-container.cc b/src/common/trace-container.cc new file mode 100644 index 000000000..95d59ff2d --- /dev/null +++ b/src/common/trace-container.cc @@ -0,0 +1,197 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "trace-container.h" +#include "packet-logger.h" +#include "trace-stream.h" +#include +#include + +namespace yans { + +TraceContainer::TraceContainer () +{} +TraceContainer::~TraceContainer () +{ + m_ui_list.erase (m_ui_list.begin (), m_ui_list.end ()); + m_si_list.erase (m_si_list.begin (), m_si_list.end ()); + m_f_list.erase (m_f_list.begin (), m_f_list.end ()); +} + +void +TraceContainer::set_ui_variable_callback (char const *name, Callback callback) +{ + for (UiListI i = m_ui_list.begin (); i != m_ui_list.end (); i++) { + if ((*i).second == name) { + (*i).first->set_callback (callback); + return; + } + } + assert (false); +} +void +TraceContainer::set_si_variable_callback (char const *name, Callback callback) +{ + for (SiListI i = m_si_list.begin (); i != m_si_list.end (); i++) { + if ((*i).second == name) { + (*i).first->set_callback (callback); + return; + } + } + assert (false); +} +void +TraceContainer::set_f_variable_callback (char const *name, Callback callback) +{ + assert (false); +} +void +TraceContainer::set_packet_logger_callback (char const *name, Callback callback) +{ + for (PacketLoggerListI i = m_packet_logger_list.begin (); i != m_packet_logger_list.end (); i++) { + if ((*i).second == name) { + (*i).first->set_callback (callback); + return; + } + } + assert (false); +} +void +TraceContainer::set_stream (char const *name, std::ostream *os) +{ + for (TraceStreamListI i = m_trace_stream_list.begin (); i != m_trace_stream_list.end (); i++) { + if ((*i).second == name) { + (*i).first->set_stream (os); + return; + } + } + assert (false); +} + +void +TraceContainer::register_ui_variable (char const *name, UiTracedVariableBase *var) +{ + // ensure unicity + for (UiListI i = m_ui_list.begin (); i != m_ui_list.end (); i++) { + if (i->second == name) { + m_ui_list.erase (i); + break; + } + } + m_ui_list.push_back (std::make_pair (var, name)); +} +void +TraceContainer::register_si_variable (char const *name, SiTracedVariableBase *var) +{ + // ensure unicity + for (SiListI i = m_si_list.begin (); i != m_si_list.end (); i++) { + if (i->second == name) { + m_si_list.erase (i); + break; + } + } + m_si_list.push_back (std::make_pair (var, name)); +} +void +TraceContainer::register_f_variable (char const *name, FTracedVariableBase *var) +{ + assert (false); +} + +void +TraceContainer::register_packet_logger (char const *name, PacketLogger *logger) +{ + // ensure unicity + for (PacketLoggerListI i = m_packet_logger_list.begin (); i != m_packet_logger_list.end (); i++) { + if (i->second == name) { + m_packet_logger_list.erase (i); + break; + } + } + m_packet_logger_list.push_back (std::make_pair (logger, name)); +} + +void +TraceContainer::register_stream (char const *name, TraceStream *stream) +{ + // ensure unicity + for (TraceStreamListI i = m_trace_stream_list.begin (); i != m_trace_stream_list.end (); i++) { + if (i->second == name) { + m_trace_stream_list.erase (i); + break; + } + } + m_trace_stream_list.push_back (std::make_pair (stream,name)); + +} + +void +TraceContainer::register_callback (char const *name, CallbackLoggerBase *logger) +{ + for (CallbackListI i = m_callback_list.begin (); i != m_callback_list.end (); i++) { + if (i->second == name) { + m_callback_list.erase (i); + break; + } + } + m_callback_list.push_back (std::make_pair (logger, name)); +} + + + + +}; // namespace yans + +#include +void +yans::TraceContainer::print_debug (void) +{ + if (!m_ui_list.empty ()) { + std::cout << "ui var: " << std::endl; + for (UiListI i = m_ui_list.begin (); i != m_ui_list.end (); i++) { + std::cout << " \"" << (*i).second << "\""<second << "\""< + */ + +#ifndef TRACE_CONTAINER_H +#define TRACE_CONTAINER_H + +#include "ui-traced-variable.tcc" +#include "si-traced-variable.tcc" +#include "f-traced-variable.tcc" +#include "callback-logger.h" +#include "yans/callback.h" +#include "packet.h" +#include +#include + +namespace yans { + +class PacketLogger; +class TraceStream; + +/** + * \brief register every source of trace events + * + * Model authors use the TraceContainer class to register + * their trace event sources. Model users use the TraceContainer + * class to connect their trace event listeners to the + * model trace event sources. + * + * TraceContainer can be used to register the following event sources: + * - yans::PacketLogger : can be connected to yans::PcapWriter + * - yans::TraceStream : can be connected to any std::ostream + * - yans::CallbackLogger: can be connected to yans::Callback + * - yans::UiTracedVariable + * - yans::SiTracedVariable + * - yans::FTracedVariable + * + * The following sample code shows how you can: + * - create trace event sources + * - register the trace event sources in a trace container + * - set event sinks to each event source + * + * \include samples/main-trace.cc + */ +class TraceContainer { +public: + TraceContainer (); + ~TraceContainer (); + + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source + * + * This method targets only event sources which are variables of any unsigned + * integer type. + */ + void set_ui_variable_callback (char const *name, + Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source + * + * This method targets only event sources which are variables of any signed + * integer type. + */ + void set_si_variable_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source + * + * This method targets only event sources which are variables of any double type. + */ + void set_f_variable_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source + * + * This method targets only event sources which are of type PacketLogger. + */ + void set_packet_logger_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param os the output stream being connected to the source trace stream + * + * This method targets only event sources which are of type TraceStream. + */ + void set_stream (char const *name, std::ostream *os); + + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source. + * + * This method targets only event sources which are of type CallbackLogger + */ + template + void set_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source. + * + * This method targets only event sources which are of type CallbackLogger + */ + template + void set_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source. + * + * This method targets only event sources which are of type CallbackLogger + */ + template + void set_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source. + * + * This method targets only event sources which are of type CallbackLogger + */ + template + void set_callback (char const *name, Callback callback); + /** + * \param name the name of the target event source + * \param callback the callback being connected to the target event source. + * + * This method targets only event sources which are of type CallbackLogger + */ + template + void set_callback (char const *name, Callback callback); + + /** + * \param name the name of the registered event source + * \param var the event source being registered + * + * This method registers only event sources of type "unsigned integer". + */ + void register_ui_variable (char const *name, UiTracedVariableBase *var); + /** + * \param name the name of the registered event source + * \param var the event source being registered + * + * This method registers only event sources of type "signed integer". + */ + void register_si_variable (char const *name, SiTracedVariableBase *var); + /** + * \param name the name of the registered event source + * \param var the event source being registered + * + * This method registers only event sources of type "double". + */ + void register_f_variable (char const *name, FTracedVariableBase *var); + /** + * \param name the name of the registered event source + * \param logger the event source being registered + * + * This method registers only event sources of type PacketLogger. + */ + void register_packet_logger (char const *name, PacketLogger *logger); + /** + * \param name the name of the registered event source + * \param stream the event source being registered + * + * This method registers only event sources of type TraceStream. + */ + void register_stream (char const *name, TraceStream *stream); + + /** + * \param name the name of the registeref event source + * \param logger the callback logger being registered. + * + * This method registers only event sources of type CallbackLogger + */ + void register_callback (char const *name, CallbackLoggerBase*logger); + + /** + * Print the list of registered event sources in this container only. + */ + void print_debug (void); +private: + typedef std::list > UiList; + typedef std::list >::iterator UiListI; + typedef std::list > SiList; + typedef std::list >::iterator SiListI; + typedef std::list > FList; + typedef std::list >::iterator FListI; + typedef std::list > PacketLoggerList; + typedef std::list >::iterator PacketLoggerListI; + typedef std::list > TraceStreamList; + typedef std::list >::iterator TraceStreamListI; + typedef std::list > CallbackList; + typedef std::list >::iterator CallbackListI; + + UiList m_ui_list; + SiList m_si_list; + FList m_f_list; + PacketLoggerList m_packet_logger_list; + TraceStreamList m_trace_stream_list; + CallbackList m_callback_list; +}; + +}; // namespace yans + +#ifndef NDEBUG +#include +#endif + +namespace yans { + +template +void +TraceContainer::set_callback (char const *name, Callback callback) +{ + for (CallbackListI i = m_callback_list.begin (); i != m_callback_list.end (); i++) { + if (i->second == name) { + static_cast *> (i->first)->set_callback (callback); + return; + } + } +#ifndef NDEBUG + assert (false); +#endif +} +template +void +TraceContainer::set_callback (char const *name, Callback callback) +{ + for (CallbackListI i = m_callback_list.begin (); i != m_callback_list.end (); i++) { + if (i->second == name) { + static_cast *> (i->first)->set_callback (callback); + return; + } + } +#ifndef NDEBUG + assert (false); +#endif +} +template +void +TraceContainer::set_callback (char const *name, Callback callback) +{ + for (CallbackListI i = m_callback_list.begin (); i != m_callback_list.end (); i++) { + if (i->second == name) { + static_cast *> (i->first)->set_callback (callback); + return; + } + } +#ifndef NDEBUG + assert (false); +#endif +} +template +void +TraceContainer::set_callback (char const *name, Callback callback) +{ + for (CallbackListI i = m_callback_list.begin (); i != m_callback_list.end (); i++) { + if (i->second == name) { + static_cast *> (i->first)->set_callback (callback); + return; + } + } +#ifndef NDEBUG + assert (false); +#endif +} +template +void +TraceContainer::set_callback (char const *name, Callback callback) +{ + for (CallbackListI i = m_callback_list.begin (); i != m_callback_list.end (); i++) { + if (i->second == name) { + static_cast *> (i->first)->set_callback (callback); + return; + } + } +#ifndef NDEBUG + assert (false); +#endif +} + + +}; // namespace yans + +#endif /* TRACED_VARIABLE_CONTAINER_H */ diff --git a/src/common/trace-stream-test.cc b/src/common/trace-stream-test.cc new file mode 100644 index 000000000..4196e7555 --- /dev/null +++ b/src/common/trace-stream-test.cc @@ -0,0 +1,68 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "trace-stream.h" +#include "yans/test.h" +#include + +#ifdef RUN_SELF_TESTS + +namespace { + +class TestTraceStream : public yans::Test { +public: + TestTraceStream (); + virtual bool run_tests (void); +}; + +static TestTraceStream g_test_stream; + +TestTraceStream::TestTraceStream () + : Test ("TraceStream") +{} + +bool +TestTraceStream::run_tests (void) +{ + bool ok = true; + yans::TraceStream trace; + //trace.set_stream (&std::cout); + trace << 1; + trace << " X "; + trace << 1.0; + trace << std::endl; + trace << "test "; + trace << 1 << " test"; + trace << "test " + << 1.0 << " " + << 0xdeadbead + << std::endl; + trace << "0x" << std::hex + << 0xdeadbeaf + << std::dec << " " + << 0xdeadbeaf + << std::endl; + return ok; +} + + +}; // namespace yans + +#endif /* RUN_SELF_TESTS */ diff --git a/src/common/trace-stream.h b/src/common/trace-stream.h new file mode 100644 index 000000000..df9493d95 --- /dev/null +++ b/src/common/trace-stream.h @@ -0,0 +1,73 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef TRACE_STREAM_H +#define TRACE_STREAM_H + +#include + +namespace yans { + +/** + * \brief log arbitrary data to std::ostreams + * + * Whenever operator << is invoked on this class, + * it is forwarded to the stored std::ostream output + * stream (if there is one). + */ +class TraceStream { +public: + TraceStream () + : m_os (0) {} + template + TraceStream &operator << (T const&v) { + if (m_os != 0) { + (*m_os) << v; + } + return *this; + } + template + TraceStream &operator << (T &v) { + if (m_os != 0) { + (*m_os) << v; + } + return *this; + } + TraceStream &operator << (std::ostream &(*v) (std::ostream &)) { + if (m_os != 0) { + (*m_os) << v; + } + return *this; + } + + /** + * \param os the output stream to store + */ + void set_stream (std::ostream * os) { + m_os = os; + } +private: + std::ostream *m_os; +}; + +}; // namespace yans + + +#endif /* TRACE_STREAM_H */ diff --git a/src/common/traced-variable-test.cc b/src/common/traced-variable-test.cc new file mode 100644 index 000000000..a195a62ee --- /dev/null +++ b/src/common/traced-variable-test.cc @@ -0,0 +1,252 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "ui-traced-variable.tcc" +#include "si-traced-variable.tcc" +#include "yans/test.h" +#include "yans/callback.h" + + +namespace yans { + +class Foo { +public: + void notify (uint64_t old_val, uint64_t new_val) {} +}; + +class TracedVariableTest: public Test { +public: + TracedVariableTest (); + void run_unsigned_tests (void); + void run_signed_unsigned_tests (void); + virtual bool run_tests (void); +}; +void +TracedVariableTest::run_unsigned_tests (void) +{ + UiTracedVariable var, ovar, tmp; + uint32_t utmp; + Foo *foo = new Foo (); + + var.set_callback (make_callback (&Foo::notify, foo)); + + var = 10; + ovar = var; + + if (var == ovar) { + } + if (var != ovar) { + } + if (var > ovar) { + } + if (var >= ovar) { + } + if (var < ovar) { + } + if (var <= ovar) { + } + + if (var == 1) { + } + if (var != 1) { + } + if (var > 1) { + } + if (var >= 1) { + } + if (var < 1) { + } + if (var <= 1) { + } + + if (1 == ovar) { + } + if (1 != ovar) { + } + if (1 > ovar) { + } + if (1 >= ovar) { + } + if (1 < ovar) { + } + if (1 <= ovar) { + } + + var++; + ++var; + var--; + --var; + + tmp = var + ovar; + tmp = var - ovar; + tmp = var / ovar; + tmp = var * ovar; + tmp = var << ovar; + tmp = var >> ovar; + tmp = var & ovar; + tmp = var | ovar; + tmp = var ^ ovar; + + tmp = var + 1; + tmp = var - 1; + tmp = var / 1; + tmp = var * 1; + tmp = var << 1; + tmp = var >> 1; + tmp = var & 1; + tmp = var | 1; + tmp = var ^ 1; + + tmp = 1 + ovar; + tmp = 1 - ovar; + tmp = 1 / ovar; + tmp = 1 * ovar; + tmp = 1 << ovar; + tmp = 1 >> ovar; + tmp = 1 & ovar; + tmp = 1 | ovar; + tmp = 1 ^ ovar; + + tmp += var; + tmp -= var; + tmp /= var; + tmp *= var; + tmp <<= var; + tmp >>= var; + tmp &= var; + tmp |= var; + tmp ^= var; + + tmp += 1; + tmp -= 1; + tmp /= 1; + tmp *= 1; + tmp <<= 1; + tmp >>= 1; + tmp &= 1; + tmp |= 1; + tmp ^= 1; + + + utmp = var + ovar; + utmp = var - ovar; + utmp = var / ovar; + utmp = var * ovar; + utmp = var << ovar; + utmp = var >> ovar; + utmp = var & ovar; + utmp = var | ovar; + utmp = var ^ ovar; + + utmp = var + 1; + utmp = var - 1; + utmp = var / 1; + utmp = var * 1; + utmp = var << 1; + utmp = var >> 1; + utmp = var & 1; + utmp = var | 1; + utmp = var ^ 1; + + utmp = 1 + ovar; + utmp = 1 - ovar; + utmp = 1 / ovar; + utmp = 1 * ovar; + utmp = 1 << ovar; + utmp = 1 >> ovar; + utmp = 1 & ovar; + utmp = 1 | ovar; + utmp = 1 ^ ovar; + + utmp += var; + utmp -= var; + utmp /= var; + utmp *= var; + utmp <<= var; + utmp >>= var; + utmp &= var; + utmp |= var; + utmp ^= var; + + utmp += 1; + utmp -= 1; + utmp /= 1; + utmp *= 1; + utmp <<= 1; + utmp >>= 1; + utmp &= 1; + utmp |= 1; + utmp ^= 1; +} + +void +TracedVariableTest::run_signed_unsigned_tests (void) +{ + unsigned short utmp = 10; + unsigned int uitmp = 7; + short stmp = 5; + utmp = stmp; + utmp += stmp; + uitmp = utmp; + utmp = uitmp; + + UiTracedVariable uvar = 10; + UiTracedVariable uivar = 5; + SiTracedVariable svar = 5; + SiTracedVariable sivar = 5; + uvar = svar; + svar = uvar; + uvar += svar; + svar += uvar; + + uvar = sivar; + sivar = uvar; + uvar += sivar; + sivar += uvar; + + uivar = uvar; + uvar = uivar; + uivar += uvar; + uvar += uivar; + + sivar = svar; + svar = sivar; + sivar += svar; + svar += sivar; +} + +bool +TracedVariableTest::run_tests (void) +{ + run_unsigned_tests (); + run_signed_unsigned_tests (); + + return true; +} + +TracedVariableTest::TracedVariableTest () + : Test ("TracedVariable") {} + +static TracedVariableTest g_traced_variable_test; + +}; // namespace yans + + diff --git a/src/common/ui-traced-variable.tcc b/src/common/ui-traced-variable.tcc new file mode 100644 index 000000000..4ab31b62f --- /dev/null +++ b/src/common/ui-traced-variable.tcc @@ -0,0 +1,239 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef UI_TRACED_VARIABLE_TCC +#define UI_TRACED_VARIABLE_TCC + +#include "yans/callback.h" +#include + +namespace yans { + +class UiTracedVariableBase { +public: + typedef Callback ChangeNotifyCallback; + + UiTracedVariableBase () + : m_callback () {} + /* We don't want to copy the base callback. Only set_callback on + * a specific instance will do something to it. */ + UiTracedVariableBase (UiTracedVariableBase const &o) + : m_callback () {} + UiTracedVariableBase &operator = (UiTracedVariableBase const &o) { + return *this; + } + ~UiTracedVariableBase () {} + + void set_callback(ChangeNotifyCallback callback) { + m_callback = callback; + } +protected: + void notify (uint64_t old_val, uint64_t new_val) { + if (old_val != new_val && !m_callback.is_null ()) { + m_callback (old_val, new_val); + } + } +private: + ChangeNotifyCallback m_callback; +}; + +template +class SiTracedVariable; + + +/** + * \brief trace variables of type "unsigned integer" + * + * This template class implements a POD type: it + * behaves like any other variable of type "unsigned integer" + * except that it also reports any changes to its + * value with its internal callback. + * + * To instantiate a 32-bit unsigned variable (to store + * a TCP counter for example), you would create a variable of type + * yans::UiTracedVariable : + \code + #include + #include "yans/ui-traced-variable.tcc" + + yans::UiTracedVariable var; + \endcode + * and you would use it like any other variable of type uint32_t: + \code + var += 12; + var = 10; + \endcode + */ +template +class UiTracedVariable : public UiTracedVariableBase { +public: + UiTracedVariable () + : m_var () + {} + UiTracedVariable (T const &var) + : m_var (var) + {} + + UiTracedVariable &operator = (UiTracedVariable const &o) { + assign (o.get ()); + return *this; + } + template + UiTracedVariable &operator = (UiTracedVariable const &o) { + assign (o.get ()); + return *this; + } + template + UiTracedVariable &operator = (SiTracedVariable const &o) { + assign (o.get ()); + return *this; + } + UiTracedVariable &operator++ () { + assign (get () + 1); + return *this; + } + UiTracedVariable &operator-- () { + assign (get () - 1); + return *this; + } + UiTracedVariable operator++ (int) { + UiTracedVariable old (*this); + ++*this; + return old; + } + UiTracedVariable operator-- (int) { + UiTracedVariable old (*this); + --*this; + return old; + } + operator T () const { + return get (); + } + + + void assign (T var) { + notify (m_var, var); + m_var = var; + } + T get (void) const { + return m_var; + } + +private: + T m_var; +}; + +template +UiTracedVariable &operator += (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () + rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator -= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () - rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator *= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () * rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator /= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () / rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator <<= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () << rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator >>= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () >> rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator &= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () & rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator |= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () | rhs.get ()); + return lhs; +} +template +UiTracedVariable &operator ^= (UiTracedVariable &lhs, UiTracedVariable const &rhs) { + lhs.assign (lhs.get () ^ rhs.get ()); + return lhs; +} + + +template +UiTracedVariable &operator += (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () + rhs); + return lhs; +} +template +UiTracedVariable &operator -= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () - rhs); + return lhs; +} +template +UiTracedVariable &operator *= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () * rhs); + return lhs; +} +template +UiTracedVariable &operator /= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () / rhs); + return lhs; +} +template +UiTracedVariable &operator <<= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () << rhs); + return lhs; +} +template +UiTracedVariable &operator >>= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () >> rhs); + return lhs; +} +template +UiTracedVariable &operator &= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () & rhs); + return lhs; +} +template +UiTracedVariable &operator |= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () | rhs); + return lhs; +} +template +UiTracedVariable &operator ^= (UiTracedVariable &lhs, U const &rhs) { + lhs.assign (lhs.get () ^ rhs); + return lhs; +} + +}; // namespace yans + +#endif /* UI_TRACED_VARIABLE_TCC */ diff --git a/src/common/utils.cc b/src/common/utils.cc new file mode 100644 index 000000000..c7d03e85f --- /dev/null +++ b/src/common/utils.cc @@ -0,0 +1,293 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "utils.h" + +namespace yans { + +uint16_t +utils_hton_16 (uint16_t v) +{ + uint8_t array[2]; + array[0] = (v >> 8) & 0xff; + array[1] = (v >> 0) & 0xff; + return *((uint16_t *)array); +} +uint32_t +utils_hton_32 (uint32_t v) +{ + uint8_t array[4]; + array[0] = (v >> 24) & 0xff; + array[1] = (v >> 16) & 0xff; + array[2] = (v >> 8) & 0xff; + array[3] = (v >> 0) & 0xff; + return *((uint32_t *)array); +} +uint16_t +utils_ntoh_16 (uint16_t v) +{ + uint16_t val; + uint8_t *array; + array = (uint8_t *)&v; + val = (array[0] << 8) | (array[1] << 0); + return val; +} +uint32_t +utils_ntoh_32 (uint32_t v) +{ + uint32_t val = 0; + uint8_t *array = (uint8_t *)&v; + val |= array[0] << 24; + val |= array[1] << 16; + val |= array[2] << 8; + val |= array[3] << 0; + return val; +} + +#define ASCII_DOT (0x2e) +#define ASCII_ZERO (0x30) +#define ASCII_A (0x41) +#define ASCII_Z (0x5a) +#define ASCII_a (0x61) +#define ASCII_z (0x7a) +#define ASCII_COLON (0x3a) + + +uint32_t +ascii_to_ipv4_host (char const *address) +{ + uint32_t host = 0; + while (true) { + uint8_t byte = 0; + while (*address != ASCII_DOT && + *address != 0) { + byte *= 10; + byte += *address - ASCII_ZERO; + address++; + } + host <<= 8; + host |= byte; + if (*address == 0) { + break; + } + address++; + } + return host; +} + + +char +ascii_to_low_case (char c) +{ + if (c >= ASCII_a && c <= ASCII_z) { + return c; + } else if (c >= ASCII_A && c <= ASCII_Z) { + return c + (ASCII_a - ASCII_A); + } else { + return c; + } +} +void +ascii_to_mac_network (char const *str, uint8_t address[6]) +{ + uint8_t i = 0; + while (*str != 0 && i < 6) { + uint8_t byte = 0; + while (*str != ASCII_COLON && *str != 0) { + byte <<= 4; + char low = ascii_to_low_case (*str); + if (low >= ASCII_a) { + byte |= low - ASCII_a + 10; + } else { + byte |= low - ASCII_ZERO; + } + str++; + } + address[i] = byte; + str++; + i++; + } +} + +uint16_t +utils_checksum_calculate (uint16_t checksum, uint8_t *buffer, uint16_t size) +{ + /* see RFC 1071 to understand this code. */ + uint32_t sum = checksum; + uint16_t *data = (uint16_t *) buffer; + for (uint16_t i = 0; i < (size/2); i++) { + sum += data[i]; + } + if ((size % 2) != 0) { + uint8_t tmp_buf[2]; + tmp_buf[0] = buffer[size-1]; + tmp_buf[1] = 0; + data = (uint16_t *)tmp_buf; + sum += *data; + } + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + return sum; +} + +uint16_t +utils_checksum_complete (uint16_t checksum) +{ + return ~checksum; +} + + +}; // namespace yans + + +#ifdef RUN_SELF_TESTS +#include "yans/test.h" +namespace yans { + +class UtilsTest : public Test { +public: + UtilsTest (); + virtual bool run_tests (void); +private: + bool test_ipv4_ascii_to_host (char const *str, uint32_t expected); + bool test_mac_ascii (char const *str, uint8_t expected[6]); + bool test_hton_16 (uint16_t v, uint8_t expected[2]); +}; +bool +UtilsTest::test_ipv4_ascii_to_host (char const *str, uint32_t expected) +{ + if (ascii_to_ipv4_host (str) != expected) { + failure () << "Utils ascii to host --" + << " for: \"" << str << "\"" + << " expected: " << expected + << " got: " << ascii_to_ipv4_host (str) + << std::endl; + return false; + } + return true; +} + +bool +UtilsTest::test_mac_ascii (char const *str, uint8_t expected[6]) +{ + uint8_t got[6]; + ascii_to_mac_network (str, got); + for (uint8_t i = 0; i < 6; i++) { + if (got[i] != expected[i]) { + failure () << "Utils ascii to mac --" + << " for: \"" << str << "\"" + << " expected: "; + failure ().setf (std::ios::hex, std::ios::basefield); + failure () << (uint32_t)expected[0] << ":" + << (uint32_t)expected[1] << ":" + << (uint32_t)expected[2] << ":" + << (uint32_t)expected[3] << ":" + << (uint32_t)expected[4] << ":" + << (uint32_t)expected[5]; + failure ().setf (std::ios::dec, std::ios::basefield); + failure () << " got: "; + failure ().setf (std::ios::hex, std::ios::basefield); + failure () << (uint32_t)got[0] << ":" + << (uint32_t)got[1] << ":" + << (uint32_t)got[2] << ":" + << (uint32_t)got[3] << ":" + << (uint32_t)got[4] << ":" + << (uint32_t)got[5]; + failure ().setf (std::ios::dec, std::ios::basefield); + failure () << std::endl; + return false; + } + } + return true; +} + +bool +UtilsTest::test_hton_16 (uint16_t v, uint8_t expected[2]) +{ + uint16_t result = utils_hton_16 (v); + uint8_t *got = (uint8_t *)&result; + if (got[0] != expected[0] || + got[1] != expected[1]) { + failure () << "Utils hton 16 --" + << " for: \"" << v << "\"" + << " expected: "; + failure ().setf (std::ios::hex, std::ios::basefield); + failure () << (uint32_t)expected[0] << ":" + << (uint32_t)expected[1]; + failure () << " got: "; + failure () << (uint32_t)got[0] << ":" + << (uint32_t)got[1]; + failure ().setf (std::ios::dec, std::ios::basefield); + failure () << std::endl; + return false; + } + return true; +} + +#define TEST_IPV4_ASCII_TO_HOST(a,b) \ +if (!test_ipv4_ascii_to_host (a,b)) { \ + ok = false; \ +} + +#define TEST_MAC_ASCII(ad, a, b, c, d, e, f) \ +{ \ + uint8_t expected[6] = {a, b, c, d, e, f}; \ + if (!test_mac_ascii (ad, expected)) { \ + ok = false; \ + } \ +} + +#define TEST_HTON_16(v, a, b) \ +{ \ + uint8_t expected[2] = {a, b}; \ + if (!test_hton_16 (v, expected)) { \ + ok = false; \ + } \ +} + + +UtilsTest::UtilsTest () + : Test ("Utils") {} + +bool +UtilsTest::run_tests (void) +{ + bool ok = true; + TEST_IPV4_ASCII_TO_HOST ("255.255.255.255", 0xffffffff); + TEST_IPV4_ASCII_TO_HOST ("255.255.255.0", 0xffffff00); + TEST_IPV4_ASCII_TO_HOST ("255.255.255.00", 0xffffff00); + TEST_IPV4_ASCII_TO_HOST ("255.255.255.000", 0xffffff00); + TEST_IPV4_ASCII_TO_HOST ("255.255.255.0000", 0xffffff00); + TEST_IPV4_ASCII_TO_HOST ("255.255.0.255", 0xffff00ff); + TEST_IPV4_ASCII_TO_HOST ("192.168.0.1", 0xc0a80001); + TEST_IPV4_ASCII_TO_HOST ("0.168.0.1", 0x00a80001); + TEST_MAC_ASCII ("00:00:00:00:00:00", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + TEST_MAC_ASCII ("00:00:00:00:00:01", 0x00, 0x00, 0x00, 0x00, 0x00, 0x01); + TEST_MAC_ASCII ("01:00:00:00:00:01", 0x01, 0x00, 0x00, 0x00, 0x00, 0x01); + TEST_MAC_ASCII ("ff:00:00:ff:00:01", 0xff, 0x00, 0x00, 0xff, 0x00, 0x01); + TEST_MAC_ASCII ("f0:00:00:00:5d:01", 0xf0, 0x00, 0x00, 0x00, 0x5d, 0x01); + TEST_HTON_16 (0xf00f, 0xf0, 0x0f); + return ok; +} +static UtilsTest g_utils_test; +}; //namespace yans +#endif /* RUN_SELF_TESTS */ diff --git a/src/common/utils.h b/src/common/utils.h new file mode 100644 index 000000000..ef38d7cd2 --- /dev/null +++ b/src/common/utils.h @@ -0,0 +1,43 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef UTILS_H +#define UTILS_H + +#include + +namespace yans { + +uint16_t utils_hton_16 (uint16_t v); +uint32_t utils_hton_32 (uint32_t v); +uint16_t utils_ntoh_16 (uint16_t v); +uint32_t utils_ntoh_32 (uint32_t v); + +uint32_t ascii_to_ipv4_host (char const *address); +void ascii_to_mac_network (char const *str, uint8_t address[6]); + +/* call with checksum = 0 the first time. */ +uint16_t utils_checksum_calculate (uint16_t checksum, uint8_t *buffer, uint16_t size); +uint16_t utils_checksum_complete (uint16_t checksum); + +}; // namespace yans + +#endif /* UTILS_H */ diff --git a/src/core/callback-test.cc b/src/core/callback-test.cc new file mode 100644 index 000000000..2ff152d3c --- /dev/null +++ b/src/core/callback-test.cc @@ -0,0 +1,197 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "test.h" +#include "callback.h" +#include + +#ifdef RUN_SELF_TESTS + +namespace yans { + +static bool g_test5 = false; +static bool g_test6 = false; +static bool g_test7 = false; + +void test5 (void) +{ + g_test5 = true; +} + +void test6 (int) +{ + g_test6 = true; +} + +int test7 (int a) +{ + g_test7 = true; + return a; +} + +class CallbackTest : public yans::Test { +private: + bool m_test1; + bool m_test2; + bool m_test3; + bool m_test4; +public: + CallbackTest (); + virtual bool run_tests (void); + void reset (void); + bool is_wrong (void); + void test1 (void); + int test2 (void); + void test3 (double a); + int test4 (double a, int b); + void test8 (Callback callback); +}; + +CallbackTest::CallbackTest () + : yans::Test ("Callback"), + m_test1 (false), + m_test2 (false), + m_test3 (false), + m_test4 (false) +{} + +void +CallbackTest::test1 (void) +{ + m_test1 = true; +} +int +CallbackTest::test2 (void) +{ + m_test2 = true; + return 2; +} +void +CallbackTest::test3 (double a) +{ + m_test3 = true; +} +int +CallbackTest::test4 (double a, int b) +{ + m_test4 = true; + return 4; +} +void +CallbackTest::test8 (Callback callback) +{ + callback (3); +} +bool +CallbackTest::is_wrong (void) +{ + if (!m_test1 || + !m_test2 || + !m_test3 || + !m_test4 || + !g_test5 || + !g_test6 || + !g_test7) { + return true; + } + return false; +} + +void +CallbackTest::reset (void) +{ + m_test1 = false; + m_test2 = false; + m_test3 = false; + m_test4 = false; + g_test5 = false; + g_test6 = false; + g_test7 = false; +} + + +bool +CallbackTest::run_tests (void) +{ + bool ok = true; + + typedef yans::Callback A; + typedef yans::Callback B; + typedef yans::Callback C; + typedef yans::Callback D; + typedef yans::Callback E; + typedef yans::Callback F; + typedef yans::Callback G; + + A a0 (this, &CallbackTest::test1); + B b0; + b0 = B (this, &CallbackTest::test2); + C c0 = C (this, &CallbackTest::test3); + D d0 = D (this, &CallbackTest::test4); + E e0 = E (&test5); + F f0 = F (&test6); + G g0 = G (&test7); + + a0 (); + b0 (); + c0 (0.0); + d0 (0.0, 1); + e0 (); + f0 (1); + g0 (1); + + if (is_wrong ()) { + ok = false; + } + + reset (); + + A a1 = yans::make_callback (&CallbackTest::test1, this); + B b1 = yans::make_callback (&CallbackTest::test2, this); + C c1 = yans::make_callback (&CallbackTest::test3, this); + D d1 = yans::make_callback (&CallbackTest::test4, this); + E e1 = yans::make_callback (&test5); + F f1 = yans::make_callback (&test6); + G g1 = yans::make_callback (&test7); + + a1 (); + b1 (); + c1 (0.0); + d1 (0.0, 1); + e1 (); + f1 (1); + g1 (2); + + test8 (f1); + + Callback a2; + + if (is_wrong ()) { + ok = false; + } + return ok; +} + +static CallbackTest g_callback_test; + +}; // namespace + +#endif /* RUN_SELF_TESTS */ diff --git a/src/core/callback.h b/src/core/callback.h new file mode 100644 index 000000000..966e8ec1d --- /dev/null +++ b/src/core/callback.h @@ -0,0 +1,518 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef CALLBACK_H +#define CALLBACK_H + +#include "reference-list.h" + +namespace yans { + +/*** + * \internal + * This code was originally written based on the techniques + * described in http://www.codeproject.com/cpp/TTLFunction.asp + * It was subsequently rewritten to follow the architecture + * outlined in "Modern C++ Design" by Andrei Alexandrescu in + * chapter 5, "Generalized Functors". + * + * This code uses: + * - default template parameters to saves users from having to + * specify empty parameters when the number of parameters + * is smaller than the maximum supported number + * - the pimpl idiom: the Callback class is passed around by + * value and delegates the crux of the work to its pimpl + * pointer. + * - two pimpl implementations which derive from CallbackImpl + * FunctorCallbackImpl can be used with any functor-type + * while MemPtrCallbackImpl can be used with pointers to + * member functions. + * - a reference list implementation to implement the Callback's + * value semantics. + * + * This code most notably departs from the alexandrescu + * implementation in that it does not use type lists to specify + * and pass around the types of the callback arguments. + * Of course, it also does not use copy-destruction semantics + * and relies on a reference list rather than auto_ptr to hold + * the pointer. + */ +class empty {}; + +// declare the CallbackImpl class +template +class CallbackImpl; +// define CallbackImpl for 0 params +template +class CallbackImpl { +public: + virtual ~CallbackImpl () {} + virtual R operator() (void) = 0; +}; +// define CallbackImpl for 1 params +template +class CallbackImpl { +public: + virtual ~CallbackImpl () {} + virtual R operator() (T1) = 0; +}; +// define CallbackImpl for 2 params +template +class CallbackImpl { +public: + virtual ~CallbackImpl () {} + virtual R operator() (T1, T2) = 0; +}; +// define CallbackImpl for 3 params +template +class CallbackImpl { +public: + virtual ~CallbackImpl () {} + virtual R operator() (T1, T2, T3) = 0; +}; +// define CallbackImpl for 4 params +template +class CallbackImpl { +public: + virtual ~CallbackImpl () {} + virtual R operator() (T1, T2, T3, T4) = 0; +}; +// define CallbackImpl for 5 params +template +class CallbackImpl { +public: + virtual ~CallbackImpl () {} + virtual R operator() (T1, T2, T3, T4, T5) = 0; +}; + + +// an impl for Functors: +template +class FunctorCallbackImpl : public CallbackImpl { +public: + FunctorCallbackImpl (T const &functor) + : m_functor (functor) {} + virtual ~FunctorCallbackImpl () {} + R operator() (void) { + return m_functor (); + } + R operator() (T1 a1) { + return m_functor (a1); + } + R operator() (T1 a1,T2 a2) { + return m_functor (a1,a2); + } + R operator() (T1 a1,T2 a2,T3 a3) { + return m_functor (a1,a2,a3); + } + R operator() (T1 a1,T2 a2,T3 a3,T4 a4) { + return m_functor (a1,a2,a3,a4); + } + R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) { + return m_functor (a1,a2,a3,a4,a5); + } +private: + T m_functor; +}; + +// an impl for Bound Functors: +template +class BoundFunctorCallbackImpl : public CallbackImpl { +public: + BoundFunctorCallbackImpl (T const &functor, TX a) + : m_functor (functor), m_a (a) {} + virtual ~BoundFunctorCallbackImpl () {} + R operator() (void) { + return m_functor (m_a); + } + R operator() (T1 a1) { + return m_functor (m_a,a1); + } + R operator() (T1 a1,T2 a2) { + return m_functor (m_a,a1,a2); + } + R operator() (T1 a1,T2 a2,T3 a3) { + return m_functor (m_a,a1,a2,a3); + } + R operator() (T1 a1,T2 a2,T3 a3,T4 a4) { + return m_functor (m_a,a1,a2,a3,a4); + } + R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) { + return m_functor (m_a,a1,a2,a3,a4,a5); + } +private: + T m_functor; + TX m_a; +}; + + +// an impl for pointer to member functions +template +class MemPtrCallbackImpl : public CallbackImpl { +public: + MemPtrCallbackImpl (OBJ_PTR const&obj_ptr, MEM_PTR mem_ptr) + : m_obj_ptr (obj_ptr), m_mem_ptr (mem_ptr) {} + virtual ~MemPtrCallbackImpl () {} + R operator() (void) { + return ((*m_obj_ptr).*m_mem_ptr) (); + } + R operator() (T1 a1) { + return ((*m_obj_ptr).*m_mem_ptr) (a1); + } + R operator() (T1 a1,T2 a2) { + return ((*m_obj_ptr).*m_mem_ptr) (a1,a2); + } + R operator() (T1 a1,T2 a2,T3 a3) { + return ((*m_obj_ptr).*m_mem_ptr) (a1,a2,a3); + } + R operator() (T1 a1,T2 a2,T3 a3,T4 a4) { + return ((*m_obj_ptr).*m_mem_ptr) (a1,a2,a3,a4); + } + R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) { + return ((*m_obj_ptr).*m_mem_ptr) (a1,a2,a3,a4,a5); + } +private: + OBJ_PTR const m_obj_ptr; + MEM_PTR m_mem_ptr; +}; + +/** + * \brief Callback template class + * + * This class template implements the Functor Design Pattern. + * It is used to declare the type of a Callback: + * - the first non-optional template argument represents + * the return type of the callback. + * - the second optional template argument represents + * the type of the first argument to the callback. + * - the third optional template argument represents + * the type of the second argument to the callback. + * - the fourth optional template argument represents + * the type of the third argument to the callback. + * - the fifth optional template argument represents + * the type of the fourth argument to the callback. + * - the sixth optional template argument represents + * the type of the fifth argument to the callback. + * + * Callback instances are built with the \ref make_callback + * template functions. Callback instances have POD semantics: + * the memory they allocate is managed automatically, without + * user intervention which allows you to pass around Callback + * instances by value. + * + * Sample code which shows how to use this class template + * as well as the function templates \ref make_callback : + * \include samples/main-callback.cc + */ +template +class Callback { +public: + template + Callback (FUNCTOR const &functor) + : m_impl (new FunctorCallbackImpl (functor)) + {} + + template + Callback (OBJ_PTR const &obj_ptr, MEM_PTR mem_ptr) + : m_impl (new MemPtrCallbackImpl (obj_ptr, mem_ptr)) + {} + + Callback (ReferenceList *> const &impl) + : m_impl (impl) + {} + + bool is_null (void) { + return (m_impl.get () == 0)?true:false; + } + + Callback () : m_impl () {} + R operator() (void) { + return (*(m_impl.get ())) (); + } + R operator() (T1 a1) { + return (*(m_impl.get ())) (a1); + } + R operator() (T1 a1, T2 a2) { + return (*(m_impl).get ()) (a1,a2); + } + R operator() (T1 a1, T2 a2, T3 a3) { + return (*(m_impl).get ()) (a1,a2,a3); + } + R operator() (T1 a1, T2 a2, T3 a3, T4 a4) { + return (*(m_impl).get ()) (a1,a2,a3,a4); + } + R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) { + return (*(m_impl).get ()) (a1,a2,a3,a4,a5); + } +private: + ReferenceList*> m_impl; +}; + +/** + * \defgroup make_callback make_callback + * + */ + +/** + * \ingroup make_callback + * \param mem_ptr class method member pointer + * \param obj_ptr class instance + * \return a wrapper Callback + * Build Callbacks for class method members which takes no arguments + * and potentially return a value. + */ +template +Callback make_callback (R (OBJ::*mem_ptr) (), OBJ *const obj_ptr) { + return Callback (obj_ptr, mem_ptr); +} +/** + * \ingroup make_callback + * \param mem_ptr class method member pointer + * \param obj_ptr class instance + * \return a wrapper Callback + * Build Callbacks for class method members which takes one argument + * and potentially return a value. + */ +template +Callback make_callback (R (OBJ::*mem_ptr) (T1), OBJ *const obj_ptr) { + return Callback (obj_ptr, mem_ptr); +} +/** + * \ingroup make_callback + * \param mem_ptr class method member pointer + * \param obj_ptr class instance + * \return a wrapper Callback + * Build Callbacks for class method members which takes two arguments + * and potentially return a value. + */ +template +Callback make_callback (R (OBJ::*mem_ptr) (T1,T2), OBJ *const obj_ptr) { + return Callback (obj_ptr, mem_ptr); +} +/** + * \ingroup make_callback + * \param mem_ptr class method member pointer + * \param obj_ptr class instance + * \return a wrapper Callback + * Build Callbacks for class method members which takes three arguments + * and potentially return a value. + */ +template +Callback make_callback (R (OBJ::*mem_ptr) (T1,T2,T3), OBJ *const obj_ptr) { + return Callback (obj_ptr, mem_ptr); +} +/** + * \ingroup make_callback + * \param mem_ptr class method member pointer + * \param obj_ptr class instance + * \return a wrapper Callback + * Build Callbacks for class method members which takes four arguments + * and potentially return a value. + */ +template +Callback make_callback (R (OBJ::*mem_ptr) (T1,T2,T3,T4), OBJ *const obj_ptr) { + return Callback (obj_ptr, mem_ptr); +} +/** + * \ingroup make_callback + * \param mem_ptr class method member pointer + * \param obj_ptr class instance + * \return a wrapper Callback + * Build Callbacks for class method members which takes five arguments + * and potentially return a value. + */ +template +Callback make_callback (R (OBJ::*mem_ptr) (T1,T2,T3,T4,T5), OBJ *const obj_ptr) { + return Callback (obj_ptr, mem_ptr); +} + +/** + * \ingroup make_callback + * \param fn_ptr function pointer + * \return a wrapper Callback + * Build Callbacks for functions which takes no arguments + * and potentially return a value. + */ +template +Callback make_callback (R (*fn_ptr) ()) { + return Callback (fn_ptr); +} +/** + * \ingroup make_callback + * \param fn_ptr function pointer + * \return a wrapper Callback + * Build Callbacks for functions which takes one argument + * and potentially return a value. + */ +template +Callback make_callback (R (*fn_ptr) (T1)) { + return Callback (fn_ptr); +} +/** + * \ingroup make_callback + * \param fn_ptr function pointer + * \return a wrapper Callback + * Build Callbacks for functions which takes two arguments + * and potentially return a value. + */ +template +Callback make_callback (R (*fn_ptr) (T1,T2)) { + return Callback (fn_ptr); +} +/** + * \ingroup make_callback + * \param fn_ptr function pointer + * \return a wrapper Callback + * Build Callbacks for functions which takes three arguments + * and potentially return a value. + */ +template +Callback make_callback (R (*fn_ptr) (T1,T2,T3)) { + return Callback (fn_ptr); +} +/** + * \ingroup make_callback + * \param fn_ptr function pointer + * \return a wrapper Callback + * Build Callbacks for functions which takes four arguments + * and potentially return a value. + */ +template +Callback make_callback (R (*fn_ptr) (T1,T2,T3,T4)) { + return Callback (fn_ptr); +} +/** + * \ingroup make_callback + * \param fn_ptr function pointer + * \return a wrapper Callback + * Build Callbacks for functions which takes five arguments + * and potentially return a value. + */ +template +Callback make_callback (R (*fn_ptr) (T1,T2,T3,T4,T5)) { + return Callback (fn_ptr); +} + + + +/** + * \ingroup make_callback + * \return a wrapper Callback + * Build a null callback which takes no arguments + * and potentially return a value. + */ +template +Callback make_null_callback (void) { + return Callback (); +} +/** + * \ingroup make_callback + * \return a wrapper Callback + * Build a null callback which takes one argument + * and potentially return a value. + */ +template +Callback make_null_callback (void) { + return Callback (); +} +/** + * \ingroup make_callback + * \return a wrapper Callback + * Build a null callback which takes two arguments + * and potentially return a value. + */ +template +Callback make_null_callback (void) { + return Callback (); +} +/** + * \ingroup make_callback + * \return a wrapper Callback + * Build a null callback which takes three arguments + * and potentially return a value. + */ +template +Callback make_null_callback (void) { + return Callback (); +} +/** + * \ingroup make_callback + * \return a wrapper Callback + * Build a null callback which takes four arguments + * and potentially return a value. + */ +template +Callback make_null_callback (void) { + return Callback (); +} +/** + * \ingroup make_callback + * \return a wrapper Callback + * Build a null callback which takes five arguments + * and potentially return a value. + */ +template +Callback make_null_callback (void) { + return Callback (); +} + +template +Callback make_bound_callback (R (*fn_ptr) (TX,T1), TX a) { + ReferenceList*> impl = + ReferenceList*> ( + new BoundFunctorCallbackImpl (fn_ptr, a) + ); + return Callback (impl); +} +template +Callback make_bound_callback (R (*fn_ptr) (TX,T1,T2), TX a) { + ReferenceList*> impl = + ReferenceList*> ( + new BoundFunctorCallbackImpl (fn_ptr, a) + ); + return Callback (impl); +} +template +Callback make_bound_callback (R (*fn_ptr) (TX,T1,T2,T3,T4), TX a) { + ReferenceList*> impl = + ReferenceList*> ( + new BoundFunctorCallbackImpl (fn_ptr, a) + ); + return Callback (impl); +} + +template +Callback make_bound_callback (R (*fn_ptr) (TX,T1,T2,T3,T4,T5), TX a) { + ReferenceList*> impl = + ReferenceList*> ( + new BoundFunctorCallbackImpl (fn_ptr, a) + ); + return Callback (impl); +} + + +}; // namespace yans + + +#endif /* CALLBACK_H */ diff --git a/src/core/exec-commands.h b/src/core/exec-commands.h new file mode 100644 index 000000000..fb74a5bf6 --- /dev/null +++ b/src/core/exec-commands.h @@ -0,0 +1,58 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef EXEC_COMMANDS_H +#define EXEC_COMMANDS_H + +#include +#include +#include +#include "callback.h" + +namespace yans { + +class ExecCommandsPrivate; + +class Command { +public: + void reset (void); + void append (std::string arg); + uint32_t get_n (void); + char const *get (uint32_t i); +private: + typedef std::vector Args; + Args m_args; +}; + +class ExecCommands { +public: + typedef Callback CommandCallback; + ExecCommands (uint32_t pool_size); + void enable_log (char const *main_log); + void add (Command command, char const *id); + void start (void); + uint32_t get_size (void); +private: + ExecCommandsPrivate *m_priv; +}; + +}; + +#endif /* EXEC_COMMANDS_H */ diff --git a/src/core/reference-list-test.cc b/src/core/reference-list-test.cc new file mode 100644 index 000000000..51746f753 --- /dev/null +++ b/src/core/reference-list-test.cc @@ -0,0 +1,120 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "reference-list.h" +#include "test.h" + +#ifdef RUN_SELF_TESTS + +#define noREFTEST_DEBUG 1 + +#ifdef REFTEST_DEBUG +#include +#define TRACE(x) \ + std::cout << x << std::endl; +#else +#define TRACE(x) +#endif + +namespace { + +class A { +public: + A () { + TRACE ("constructor"); + } + ~A () { + TRACE ("destructor"); + } + void trace (void) { + TRACE ("trace"); + } +}; + +class RefTest : public yans::Test { +public: + RefTest (); + virtual bool run_tests (void); +private: + void test (yans::ReferenceList); +}; + +RefTest::RefTest () + : yans::Test ("ReferenceList") +{} + +void +RefTest::test (yans::ReferenceList a) +{ + a->trace (); +} + +bool +RefTest::run_tests (void) +{ + bool ok = true; + + { + yans::ReferenceList tmp; + { + yans::ReferenceList a (new A ()); + + test (a); + tmp = a; + test (tmp); + a = tmp; + test (a); + TRACE ("leave inner scope"); + } + test (tmp); + TRACE ("leave outer scope"); + } + + { + yans::ReferenceList tmp; + } + + { + yans::ReferenceList tmp (new A ()); + } + + { + yans::ReferenceList tmp; + tmp.set (new A ()); + } + + { + TRACE ("test assignement"); + yans::ReferenceList a0 (new A ()); + yans::ReferenceList a1 (new A ()); + a0 = a1; + } + + + + return ok; +} + + +static RefTest g_ref_test = RefTest (); + +}; // namespace + +#endif /* RUN_SELF_TESTS */ diff --git a/src/core/reference-list.h b/src/core/reference-list.h new file mode 100644 index 000000000..d2bc95eb0 --- /dev/null +++ b/src/core/reference-list.h @@ -0,0 +1,117 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef REFERENCE_LIST_H +#define REFERENCE_LIST_H + +/* This is a reference list implementation. The technique underlying + * this code was first described in 1995 by Risto Lankinen on Usenet + * but I have never been able to find his original posting. Instead, + * this code is based on the description of the technique found in + * "Modern C++ design" by Andrei Alexandrescu in chapter 7. + */ + + +namespace yans { + +template +class ReferenceList; + +template +class ReferenceList { +public: + ReferenceList () + : m_obj_ptr (), + m_prev (), + m_next () + { + m_prev = this; + m_next = this; + } + ReferenceList (ReferenceList &o) + : m_obj_ptr (), + m_prev (), + m_next () + { + m_prev = this; + m_next = this; + insert_self_in_other (o); + } + ReferenceList (ReferenceList const&o) + : m_obj_ptr (), + m_prev (), + m_next () + { + m_prev = this; + m_next = this; + insert_self_in_other (o); + } + ReferenceList (OBJ_PTR const &obj_ptr) + : m_obj_ptr (obj_ptr), + m_prev (), + m_next () + { + m_prev = this; + m_next = this; + } + ~ReferenceList () { + remove_from_list (); + } + ReferenceList & operator= (ReferenceList const&o) { + remove_from_list (); + insert_self_in_other (o); + return *this; + } + OBJ_PTR operator-> () { + return m_obj_ptr; + } + void set (OBJ_PTR obj_ptr) { + remove_from_list (); + m_obj_ptr = obj_ptr; + } + OBJ_PTR get (void) { + // explicit conversion to raw pointer type. + return m_obj_ptr; + } +private: + void insert_self_in_other (ReferenceList const&o) { + m_prev = &o; + m_next = o.m_next; + m_next->m_prev = this; + o.m_next = this; + m_obj_ptr = o.m_obj_ptr; + } + void remove_from_list (void) { + if (m_prev == this) { + //assert (m_next == this); + delete m_obj_ptr; + m_obj_ptr = OBJ_PTR (); + } + m_prev->m_next = m_next; + m_next->m_prev = m_prev; + } + OBJ_PTR m_obj_ptr; + mutable ReferenceList const*m_prev; + mutable ReferenceList const*m_next; +}; + +}; // namespace yans + +#endif /* REFERENCE_LIST_H */ diff --git a/src/core/system-file.h b/src/core/system-file.h new file mode 100644 index 000000000..e534eb708 --- /dev/null +++ b/src/core/system-file.h @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SYSTEM_FILE_H +#define SYSTEM_FILE_H + +#include + +namespace yans { + +class SystemFilePrivate; + +class SystemFile { +public: + SystemFile (); + ~SystemFile (); + + void open (char const *filename); + void write (uint8_t *buffer, uint32_t size); +private: + SystemFilePrivate *m_priv; +}; + +}; //namespace yans + +#endif /* SYSTEM_FILE_H */ diff --git a/src/core/system-mutex.h b/src/core/system-mutex.h new file mode 100644 index 000000000..c3a5e4960 --- /dev/null +++ b/src/core/system-mutex.h @@ -0,0 +1,42 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef SYSTEM_MUTEX_H +#define SYSTEM_MUTEX_H + +#include + +namespace yans { + +class SystemMutexPrivate; + +class SystemMutex { +public: + SystemMutex (); + ~SystemMutex (); + void lock (void); + void unlock (void); + private: + SystemMutexPrivate *m_priv; +}; + +}; // namespace yans + +#endif /* SYSTEM_MUTEX_H */ diff --git a/src/core/system-semaphore.h b/src/core/system-semaphore.h new file mode 100644 index 000000000..5bce291b4 --- /dev/null +++ b/src/core/system-semaphore.h @@ -0,0 +1,44 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef SYSTEM_SEMAPHORE_H +#define SYSTEM_SEMAPHORE_H + +#include + +namespace yans { + +class SystemSemaphorePrivate; + +class SystemSemaphore { +public: + SystemSemaphore (uint32_t init); + ~SystemSemaphore (); + void post (void); + void post (uint32_t n); + void wait (void); + void wait (uint32_t n); +private: + SystemSemaphorePrivate *m_priv; +}; + +}; // namespace yans + +#endif /* SYSTEM_SEMAPHORE_H */ diff --git a/src/core/system-thread.h b/src/core/system-thread.h new file mode 100644 index 000000000..82375f389 --- /dev/null +++ b/src/core/system-thread.h @@ -0,0 +1,41 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef SYSTEM_THREAD_H +#define SYSTEM_THREAD_H + +namespace yans { + +class SystemThreadPrivate; + +class SystemThread { +public: + SystemThread (); + virtual ~SystemThread (); +private: + friend class SystemThreadPrivate; + SystemThreadPrivate *m_priv; + virtual void real_run (void) = 0; +}; + +}; // namespace yans + + +#endif /* SYSTEM_THREAD_H */ diff --git a/src/core/test.cc b/src/core/test.cc new file mode 100644 index 000000000..de166957e --- /dev/null +++ b/src/core/test.cc @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "test.h" + +#ifdef RUN_SELF_TESTS +#include + +namespace yans { + +TestManager * +TestManager::get (void) +{ + static TestManager manager; + return &manager; +} + +TestManager::TestManager () + : m_verbose (false) +{} + +TestManager::~TestManager () +{ + TestsI i = m_tests.begin (); + while (i != m_tests.end ()) { + delete (*i).second; + i = m_tests.erase (i); + } +} +void +TestManager::add (Test *test, char const *name) +{ + get ()->m_tests.push_back (std::make_pair (test, new std::string (name))); +} +void +TestManager::enable_verbose (void) +{ + get ()->m_verbose = true; +} +std::ostream & +TestManager::failure (void) +{ + return std::cerr; +} +bool +TestManager::run_tests (void) +{ + return get ()->real_run_tests (); +} +bool +TestManager::real_run_tests (void) +{ + bool is_success = true; + for (TestsCI i = m_tests.begin (); i != m_tests.end (); i++) { + std::string *test_name = (*i).second; + if (!(*i).first->run_tests ()) { + is_success = false; + if (m_verbose) { + std::cerr << "FAIL " << *test_name << std::endl; + } + } else { + if (m_verbose) { + std::cerr << "PASS "<<*test_name << std::endl; + } + } + } + if (!is_success) { + std::cerr << "FAIL" << std::endl; + } + return is_success; +} + +Test::Test (char const *name) +{ + TestManager::add (this, name); +} + +Test::~Test () +{} + +std::ostream & +Test::failure (void) +{ + return TestManager::failure (); +} + +}; // namespace yans + +#endif /* RUN_SELF_TESTS */ diff --git a/src/core/test.h b/src/core/test.h new file mode 100644 index 000000000..c1b0ac244 --- /dev/null +++ b/src/core/test.h @@ -0,0 +1,75 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef TEST_H +#define TEST_H + +#include +#include +#include +#include + +#ifdef RUN_SELF_TESTS + +namespace yans { + +class TestManager; + +class Test { +public: + Test (char const *name); + virtual ~Test (); + + virtual bool run_tests (void) = 0; + +protected: + std::ostream &failure (void); +}; + +class TestManager { +public: + // main methods the test runner is supposed to + // invoke. + static void enable_verbose (void); + static bool run_tests (void); + + // helper methods + static void add (Test *test, char const *name); + static std::ostream &failure (void); +private: + static TestManager *get (void); + bool real_run_tests (void); + + TestManager (); + ~TestManager (); + + typedef std::list > Tests; + typedef std::list >::iterator TestsI; + typedef std::list >::const_iterator TestsCI; + + Tests m_tests; + bool m_verbose; +}; +}; // namespace yans + +#endif /* RUN_SELF_TESTS */ + +#endif /* TEST_H */ diff --git a/src/core/unix-exec-commands.cc b/src/core/unix-exec-commands.cc new file mode 100644 index 000000000..49e36d61b --- /dev/null +++ b/src/core/unix-exec-commands.cc @@ -0,0 +1,516 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "exec-commands.h" +#include "system-thread.h" +#include "system-semaphore.h" +#include "system-mutex.h" +#include "callback.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define noTRACE_COMMAND 1 + +#ifdef TRACE_COMMAND +#include +# define TRACE(x) \ +std::cout << "COMMAND TRACE " << x << std::endl; +#else /* TRACE_COMMAND */ +# define TRACE(format,...) +#endif /* TRACE_COMMAND */ + + +namespace yans { + +class LogThread : public SystemThread { +public: + LogThread (int main_log); + virtual ~LogThread (); + void add (int in, int out); +private: + virtual void real_run (void); + void write_to (int fd, char *buffer, int size); + typedef std::vector Fds; + typedef std::vector::iterator FdsI; + + int m_main_log; + Fds m_input_fds; + Fds m_output_fds; + SystemMutex m_fds_mutex; +}; + +LogThread::LogThread (int main_log) + : m_main_log (main_log) +{} + +LogThread::~LogThread () +{} + +void +LogThread::add (int in, int out) +{ + m_fds_mutex.lock (); + m_input_fds.push_back (in); + m_output_fds.push_back (out); + m_fds_mutex.unlock (); +} +void +LogThread::write_to (int fd, char *buffer, int to_write) +{ + while (to_write > 0) { + int written = write (fd, buffer, to_write); + to_write -= written; + buffer += written; + assert (written >= 0); + } +} + +void +LogThread::real_run (void) +{ + char buffer[1024]; + while (true) { + fd_set in; + struct timeval tv; + int retval; + + TRACE ("prepare fd set"); + m_fds_mutex.lock (); + assert (m_input_fds.size () == m_output_fds.size ()); + FD_ZERO (&in); + int max_fd = 0; + for (uint32_t i = 0; i < m_input_fds.size (); i++) { + if (m_input_fds[i] > max_fd) { + max_fd = m_input_fds[i]; + } + FD_SET (m_input_fds[i], &in); + } + m_fds_mutex.unlock (); + TRACE ("fd set prepared"); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + retval = select (max_fd+1, &in, NULL, NULL, &tv); + TRACE ("selected"); + for (uint32_t i = 0; i < m_input_fds.size (); i++) { + if (FD_ISSET (m_input_fds[i], &in)) { + retval = read (m_input_fds[i], buffer, 1024); + if (retval == 0) { + close (m_output_fds[i]); + TRACE ("closed input"); + m_fds_mutex.lock (); + FdsI cur = m_input_fds.begin (); + cur += i; + m_input_fds.erase (cur); + cur = m_output_fds.begin (); + cur += i; + m_output_fds.erase (cur); + m_fds_mutex.unlock (); + continue; + } + assert (retval > 0); + write_to (m_output_fds[i], buffer, retval); + write_to (m_main_log, buffer, retval); + } + } + TRACE ("written"); + } +} + + +class CommandSystemThread : public SystemThread { +public: + typedef Callback DoneLogCallback; + typedef Callback DoneNoLogCallback; + CommandSystemThread (); + void start_log (Command command, std::string id, DoneLogCallback callback); + void start_no_log (Command command, DoneNoLogCallback callback); + void stop (void); +private: + virtual void real_run (void); + void run_exec (void); + SystemSemaphore m_sem; + bool m_stop; + Command m_command; + std::string m_id; + DoneLogCallback m_done_log; + DoneNoLogCallback m_done_no_log; + bool m_no_log; +}; + +CommandSystemThread::CommandSystemThread () + : m_sem (0), + m_stop (false) +{} + +void +CommandSystemThread::start_no_log (Command command, DoneNoLogCallback done) +{ + m_no_log = true; + m_command = command; + m_done_no_log = done; + m_sem.post (); +} + +void +CommandSystemThread::start_log (Command command, std::string id, DoneLogCallback done) +{ + m_no_log = false; + m_command = command; + m_id = id; + m_done_log = done; + m_sem.post (); +} + +void +CommandSystemThread::stop (void) +{ + m_stop = true; + m_sem.post (); +} + +void +CommandSystemThread::run_exec (void) +{ + char ** args = (char **)malloc (sizeof (char *) * (m_command.get_n ()+1)); + char const *file = m_command.get (0); + args[0] = strdup (m_command.get (0)); + for (uint32_t i = 1; i < m_command.get_n (); i++) { + args[i] = strdup (m_command.get (i)); + //std::cout << "arg " << args[i-1] << std::endl; + } + args[m_command.get_n ()] = (char *)NULL; + int retval = execvp (file, args); + if (retval != 0) { + std::cout << strerror (errno) << std::endl; + exit (1); + } + // NOTREACHED + assert (false); +} + +void +CommandSystemThread::real_run (void) +{ + while (true) { + m_sem.wait (); + if (m_stop) { + break; + } + int retval; + int filedes[2]; + if (m_no_log) { + pid_t pid = fork (); + if (pid == -1) { + assert (false); + // error in parent fork. + } else if (pid == 0) { + retval = open ("/dev/null", O_WRONLY); + dup2 (retval, 1); + close (retval); + // success, child. + run_exec (); + } else { + // success, parent. + m_done_no_log (this); + } + } else { + retval = pipe (filedes); + assert (retval == 0); + pid_t pid = fork (); + if (pid == -1) { + assert (false); + // error in parent fork. + } else if (pid == 0) { + // success, child. + TRACE ("child"); + close (1); + close (filedes[0]); + dup2 (filedes[1], 1); + run_exec (); + } else { + TRACE ("parent"); + // success, parent. + close (filedes[1]); + m_done_log (this, filedes[0], m_id); + } + } + } +} + +class ExecCommandsPrivate { +public: + ExecCommandsPrivate (uint32_t pool_size); + ~ExecCommandsPrivate (); + void enable_log (char const *main_log); + void add (Command command, std::string id); + void start (void); + uint32_t get_size (void); +private: + struct CommandRequest { + Command m_command; + std::string m_id; + }; + typedef std::vector Threads; + typedef std::vector::iterator ThreadsI; + typedef std::vector Requests; + typedef std::vector::iterator RequestsI; + void command_done_log (CommandSystemThread *thread, int fd, std::string id); + void command_done_no_log (CommandSystemThread *thread); + + Requests m_requests; + SystemSemaphore m_n_threads; + uint32_t m_pool_size; + Threads m_threads; + SystemMutex m_threads_mutex; + int m_main_log; + LogThread *m_log; +}; + + +ExecCommandsPrivate::ExecCommandsPrivate (uint32_t pool_size) + : m_n_threads (0), + m_pool_size (pool_size), + m_main_log (0), + m_log (0) +{ + m_threads_mutex.lock (); + for (uint32_t i = 0; i < pool_size; i++) { + m_threads.push_back (new CommandSystemThread ()); + } + m_threads_mutex.unlock (); + m_n_threads.post (m_pool_size); +} + +ExecCommandsPrivate::~ExecCommandsPrivate () +{ + m_threads_mutex.lock (); + for (ThreadsI i = m_threads.begin (); i != m_threads.end (); i++) { + (*i)->stop (); + delete *i; + } + m_threads.erase (m_threads.begin (), m_threads.end ()); + m_threads_mutex.unlock (); + delete m_log; +} + +void +ExecCommandsPrivate::enable_log (char const *main_log) +{ + m_main_log = open (main_log, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + m_log = new LogThread (m_main_log); + assert (m_main_log != -1); +} + + +void +ExecCommandsPrivate::add (Command command, std::string id) +{ + struct CommandRequest request; + request.m_command = command; + request.m_id = id; + m_requests.push_back (request); +} +void +ExecCommandsPrivate::start (void) +{ + for (RequestsI i = m_requests.begin (); i != m_requests.end (); i++) { + TRACE ("wait for thread"); + m_n_threads.wait (); + m_threads_mutex.lock (); + CommandSystemThread *thread = m_threads.back (); + m_threads.pop_back (); + m_threads_mutex.unlock (); + TRACE ("start command"); + if (m_main_log != 0) { + thread->start_log (i->m_command, i->m_id, + make_callback (&ExecCommandsPrivate::command_done_log, this)); + } else { + thread->start_no_log (i->m_command, + make_callback (&ExecCommandsPrivate::command_done_no_log, this)); + } + } +} +void +ExecCommandsPrivate::command_done_log (CommandSystemThread *thread, int in, std::string id) +{ + TRACE ("command done"); + m_threads_mutex.lock (); + m_threads.push_back (thread); + m_threads_mutex.unlock (); + m_n_threads.post (); + + std::string out_filename = id; + out_filename.append (".log"); + int out_fd = open (out_filename.c_str (), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + assert (out_fd != -1); + m_log->add (in, out_fd); + TRACE ("notify command done"); +} + +void +ExecCommandsPrivate::command_done_no_log (CommandSystemThread *thread) +{ + TRACE ("command done"); + m_threads_mutex.lock (); + m_threads.push_back (thread); + m_threads_mutex.unlock (); + m_n_threads.post (); + TRACE ("notify command done"); +} + +uint32_t +ExecCommandsPrivate::get_size (void) +{ + return m_requests.size (); +} + +void +Command::reset (void) +{ + m_args.erase (m_args.begin (), m_args.end ()); +} + +void +Command::append (std::string arg) +{ + m_args.push_back (arg); +} + + +uint32_t +Command::get_n (void) +{ + return m_args.size (); +} +char const* +Command::get (uint32_t i) +{ + return m_args[i].c_str (); +} + + + +ExecCommands::ExecCommands (uint32_t pool_size) + : m_priv (new ExecCommandsPrivate (pool_size)) +{ + assert (pool_size != 0); +} +void +ExecCommands::enable_log (char const *main_log) +{ + m_priv->enable_log (main_log); +} +void +ExecCommands::add (Command command, char const *id) +{ + m_priv->add (command, id); +} +void +ExecCommands::start (void) +{ + m_priv->start (); +} + +uint32_t +ExecCommands::get_size (void) +{ + return m_priv->get_size (); +} + +}; // namespace yans + +#ifdef RUN_SELF_TESTS + +#include "test.h" +#include +#include + +namespace yans { + +class ExecCommandsTest: public Test { +public: + ExecCommandsTest (); + virtual ~ExecCommandsTest (); + virtual bool run_tests (void); +private: + void command_output (char const *data, uint32_t size); +}; + +ExecCommandsTest::ExecCommandsTest () + : Test ("ExecCommands") +{} +ExecCommandsTest::~ExecCommandsTest () +{} +void +ExecCommandsTest::command_output (char const *data, uint32_t size) +{ + for (uint32_t i = 0; i < size; i++) { + std::cout << data[i]; + }; +} +bool +ExecCommandsTest::run_tests (void) +{ + bool ok = true; +#if 0 + ExecCommands commands = ExecCommands (2); + Command command; + command.append ("ls"); + command.append ("-l"); + commands.add (command, "ls"); + + command.reset (); + command.append ("ls"); + command.append ("-l"); + command.append ("src"); + commands.add (command, "ls-src"); + + command.reset (); + command.append ("ls"); + command.append ("-l"); + command.append ("/usr/bin"); + commands.add (command, "ls-usr-bin"); + + commands.enable_log ("main.log"); + commands.start (); + sleep (5); +#endif + return ok; +} + +static ExecCommandsTest g_exec_commands_test; + +}; // namespace yans + +#endif /* RUN_SELF_TESTS */ + + diff --git a/src/core/unix-system-file.cc b/src/core/unix-system-file.cc new file mode 100644 index 000000000..25081a16a --- /dev/null +++ b/src/core/unix-system-file.cc @@ -0,0 +1,119 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "system-file.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define noTRACE_SYS_FILE 1 + +#ifdef TRACE_SYS_FILE +#include +# define TRACE(x) \ +std::cout << "SYS FILE TRACE " << this << " " << x << std::endl; +#else /* TRACE_SYS_FILE */ +# define TRACE(format,...) +#endif /* TRACE_SYS_FILE */ + +#define BUFFER_SIZE (4096) + + +namespace yans { + +class SystemFilePrivate { +public: + SystemFilePrivate (); + ~SystemFilePrivate (); + + void open (char const *filename); + void write (uint8_t *buffer, uint32_t size); +private: + uint8_t m_data[BUFFER_SIZE]; + uint32_t m_current; + int m_fd; +}; + +SystemFilePrivate::SystemFilePrivate () + : m_current (0) +{} +SystemFilePrivate::~SystemFilePrivate () +{ + ::write (m_fd, m_data, m_current); + ::close (m_fd); +} + + +void +SystemFilePrivate::open (char const *filename) +{ + m_fd = ::open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + assert (m_fd != -1); +} + +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif /* min */ + +void +SystemFilePrivate::write (uint8_t *buffer, uint32_t size) +{ + while (size > 0) { + uint32_t to_copy = min (BUFFER_SIZE - m_current, size); + memcpy (m_data + m_current, buffer, to_copy); + size -= to_copy; + m_current += to_copy; + buffer += to_copy; + if (m_current == BUFFER_SIZE) { + ssize_t written = 0; + written = ::write (m_fd, m_data, BUFFER_SIZE); + assert (written == BUFFER_SIZE); + m_current = 0; + } + } +} + +SystemFile::SystemFile () + : m_priv (new SystemFilePrivate ()) +{} +SystemFile::~SystemFile () +{ + delete m_priv; + m_priv = 0; +} + +void +SystemFile::open (char const *filename) +{ + m_priv->open (filename); +} +void +SystemFile::write (uint8_t *buffer, uint32_t size) +{ + m_priv->write (buffer, size); +} + +}; // namespace diff --git a/src/core/unix-system-mutex.cc b/src/core/unix-system-mutex.cc new file mode 100644 index 000000000..f6269c446 --- /dev/null +++ b/src/core/unix-system-mutex.cc @@ -0,0 +1,82 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "system-mutex.h" + +#include +#include + +namespace yans { + +class SystemMutexPrivate { +public: + SystemMutexPrivate (); + ~SystemMutexPrivate (); + void lock (void); + void unlock (void); +private: + pthread_mutex_t m_mutex; +}; + +SystemMutexPrivate::SystemMutexPrivate () +{ + int retval; + retval = pthread_mutex_init (&m_mutex, NULL); + assert (retval == 0); +} +SystemMutexPrivate::~SystemMutexPrivate () +{ + int retval; + retval = pthread_mutex_destroy (&m_mutex); + assert (retval == 0); +} +void +SystemMutexPrivate::lock (void) +{ + pthread_mutex_lock (&m_mutex); +} +void +SystemMutexPrivate::unlock (void) +{ + pthread_mutex_unlock (&m_mutex); +} + +SystemMutex::SystemMutex () + : m_priv (new SystemMutexPrivate ()) +{} +SystemMutex::~SystemMutex () +{ + delete m_priv; +} +void +SystemMutex::lock (void) +{ + m_priv->lock (); +} +void +SystemMutex::unlock (void) +{ + m_priv->unlock (); +} + + + +}; // namespace yans diff --git a/src/core/unix-system-semaphore.cc b/src/core/unix-system-semaphore.cc new file mode 100644 index 000000000..8286c10fa --- /dev/null +++ b/src/core/unix-system-semaphore.cc @@ -0,0 +1,114 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "system-semaphore.h" + +#include +#include +#include +#include "errno.h" +#include "string.h" + +namespace yans { + +class SystemSemaphorePrivate { +public: + SystemSemaphorePrivate (uint32_t init); + void post (void); + void post (uint32_t n); + void wait (void); + void wait (uint32_t n); +private: + sem_t m_sem; +}; + +SystemSemaphorePrivate::SystemSemaphorePrivate (uint32_t init) +{ + int retval = sem_init (&m_sem, 0, init); + if (retval == -1) { + std::cout << "sem init " << this << " " << strerror (errno) << std::endl; + } +} +void +SystemSemaphorePrivate::post (void) +{ + int retval = sem_post (&m_sem); + if (retval == -1) { + std::cout << "sem post " << this << " " << strerror (errno) << std::endl; + } +} +void +SystemSemaphorePrivate::wait (void) +{ + int retval; + do { + retval = sem_wait (&m_sem); + } while (retval == -1 && errno == EINTR); + if (retval == -1) { + std::cout << "sem wait " << this << " " << strerror (errno) << std::endl; + } +} +void +SystemSemaphorePrivate::post (uint32_t n) +{ + for (uint32_t i = 0; i < n; i++) { + post (); + } +} +void +SystemSemaphorePrivate::wait (uint32_t n) +{ + for (uint32_t i = 0; i < n; i++) { + wait (); + } +} + +SystemSemaphore::SystemSemaphore (uint32_t init) + : m_priv (new SystemSemaphorePrivate (init)) +{} +SystemSemaphore::~SystemSemaphore () +{ + delete m_priv; +} +void +SystemSemaphore::post (void) +{ + m_priv->post (); +} +void +SystemSemaphore::post (uint32_t n) +{ + m_priv->post (n); +} +void +SystemSemaphore::wait (void) +{ + m_priv->wait (); +} +void +SystemSemaphore::wait (uint32_t n) +{ + m_priv->wait (n); +} + + + +}; // namespace yans diff --git a/src/core/unix-system-thread.cc b/src/core/unix-system-thread.cc new file mode 100644 index 000000000..637163f69 --- /dev/null +++ b/src/core/unix-system-thread.cc @@ -0,0 +1,69 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "system-thread.h" + +#include +#include + +namespace yans { + +class SystemThreadPrivate { +public: + SystemThreadPrivate (SystemThread *thread); + ~SystemThreadPrivate (); +private: + static void *pthread_run (void *thread); + pthread_t m_system_thread; + SystemThread *m_thread; +}; + +SystemThreadPrivate::SystemThreadPrivate (SystemThread *thread) + : m_thread (thread) +{ + int retval; + retval = pthread_create (&m_system_thread, + NULL, + SystemThreadPrivate::pthread_run, + this); + assert (retval == 0); +} +SystemThreadPrivate::~SystemThreadPrivate () +{} +void * +SystemThreadPrivate::pthread_run (void *thread) +{ + SystemThreadPrivate *self = reinterpret_cast (thread); + self->m_thread->real_run (); + return thread; +} + +SystemThread::SystemThread () + : m_priv (new SystemThreadPrivate (this)) +{} + +SystemThread::~SystemThread () +{ + delete m_priv; +} + +}; // namespace yans + diff --git a/src/core/unix-wall-clock-ms.cc b/src/core/unix-wall-clock-ms.cc new file mode 100644 index 000000000..f1879bced --- /dev/null +++ b/src/core/unix-wall-clock-ms.cc @@ -0,0 +1,74 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "wall-clock-ms.h" +#include + +namespace yans { + +class WallClockMsPrivate { +public: + void start (void); + unsigned long long end (void); +private: + struct timeval m_start_tv; + struct timeval m_end_tv; +}; + +void +WallClockMsPrivate::start (void) +{ + struct timezone tz; + gettimeofday (&m_start_tv, &tz); +} + +unsigned long long +WallClockMsPrivate::end (void) +{ + struct timezone tz; + gettimeofday (&m_end_tv, &tz); + unsigned long long end = m_end_tv.tv_sec *1000 + m_end_tv.tv_usec / 1000; + unsigned long long start = m_start_tv.tv_sec *1000 + m_start_tv.tv_usec / 1000; + return end - start; +} + +WallClockMs::WallClockMs () + : m_priv (new WallClockMsPrivate ()) +{} + +WallClockMs::~WallClockMs () +{ + delete m_priv; + m_priv = 0; +} + +void +WallClockMs::start (void) +{ + m_priv->start (); +} +unsigned long long +WallClockMs::end (void) +{ + return m_priv->end (); +} + +}; // namespace yans diff --git a/src/core/wall-clock-ms.h b/src/core/wall-clock-ms.h new file mode 100644 index 000000000..87597ec22 --- /dev/null +++ b/src/core/wall-clock-ms.h @@ -0,0 +1,40 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef WALL_CLOCK_MS_H +#define WALL_CLOCK_MS_H + +namespace yans { + +class WallClockMs { +public: + WallClockMs (); + ~WallClockMs (); + + void start (void); + unsigned long long end (void); +private: + class WallClockMsPrivate *m_priv; +}; + +}; // namespace yans + +#endif /* WALL_CLOCK_MS_H */ diff --git a/src/core/win32-system-file.cc b/src/core/win32-system-file.cc new file mode 100644 index 000000000..ac94d6d1f --- /dev/null +++ b/src/core/win32-system-file.cc @@ -0,0 +1,86 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "system-file.h" + + +#define noTRACE_SYS_FILE 1 + +#ifdef TRACE_SYS_FILE +#include +# define TRACE(x) \ +std::cout << "SYS FILE TRACE " << this << " " << x << std::endl; +#else /* TRACE_SYS_FILE */ +# define TRACE(format,...) +#endif /* TRACE_SYS_FILE */ + +#define BUFFER_SIZE (4096) + + +namespace yans { + +class SystemFilePrivate { +public: + SystemFilePrivate (); + ~SystemFilePrivate (); + + void open (char const *filename); + void write (uint8_t *buffer, uint32_t size); +private: +}; + +SystemFilePrivate::SystemFilePrivate () +{} +SystemFilePrivate::~SystemFilePrivate () +{ +} + + +void +SystemFilePrivate::open (char const *filename) +{ +} + +void +SystemFilePrivate::write (uint8_t *buffer, uint32_t size) +{ +} + +SystemFile::SystemFile () + : m_priv (new SystemFilePrivate ()) +{} +SystemFile::~SystemFile () +{ + delete m_priv; + m_priv = 0; +} + +void +SystemFile::open (char const *filename) +{ + m_priv->open (filename); +} +void +SystemFile::write (uint8_t *buffer, uint32_t size) +{ + m_priv->write (buffer, size); +} + +}; // namespace diff --git a/src/core/win32-system-mutex.cc b/src/core/win32-system-mutex.cc new file mode 100644 index 000000000..b5344ceea --- /dev/null +++ b/src/core/win32-system-mutex.cc @@ -0,0 +1,78 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "system-mutex.h" + +#include +#include + +namespace yans { + +class SystemMutexPrivate { +public: + SystemMutexPrivate (); + ~SystemMutexPrivate (); + void lock (void); + void unlock (void); +private: + HANDLE m_mutex; +}; + +SystemMutexPrivate::SystemMutexPrivate () +{ + m_mutex = CreateMutex(NULL, FALSE, "mutex"); +} +SystemMutexPrivate::~SystemMutexPrivate () +{ + CloseHandle (m_mutex); +} +void +SystemMutexPrivate::lock (void) +{ + WaitForSingleObject (m_mutex,INFINITE); +} +void +SystemMutexPrivate::unlock (void) +{ + ReleaseMutex (m_mutex); +} + +SystemMutex::SystemMutex () + : m_priv (new SystemMutexPrivate ()) +{} +SystemMutex::~SystemMutex () +{ + delete m_priv; +} +void +SystemMutex::lock (void) +{ + m_priv->lock (); +} +void +SystemMutex::unlock (void) +{ + m_priv->unlock (); +} + + + +}; // namespace yans diff --git a/src/core/win32-system-semaphore.cc b/src/core/win32-system-semaphore.cc new file mode 100644 index 000000000..eea57aace --- /dev/null +++ b/src/core/win32-system-semaphore.cc @@ -0,0 +1,103 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "system-semaphore.h" + +#include +#include +#include + +namespace yans { + +class SystemSemaphorePrivate { +public: + SystemSemaphorePrivate (uint32_t init); + ~SystemSemaphorePrivate (); + void post (void); + void post (uint32_t n); + void wait (void); + void wait (uint32_t n); +private: + HANDLE m_sem; +}; + +SystemSemaphorePrivate::SystemSemaphorePrivate (uint32_t init) +{ + m_sem = CreateSemaphore(NULL, init, 0, "semaphore"); +} +SystemSemaphorePrivate::~SystemSemaphorePrivate () +{ + CloseHandle (m_sem); +} +void +SystemSemaphorePrivate::post (void) +{ + ReleaseSemaphore(m_sem,1,NULL); +} +void +SystemSemaphorePrivate::wait (void) +{ + WaitForSingleObject (m_sem, INFINITE); +} +void +SystemSemaphorePrivate::post (uint32_t n) +{ + ReleaseSemaphore(m_sem,n,NULL); +} +void +SystemSemaphorePrivate::wait (uint32_t n) +{ + for (uint32_t i = 0; i < n; i++) { + wait (); + } +} + +SystemSemaphore::SystemSemaphore (uint32_t init) + : m_priv (new SystemSemaphorePrivate (init)) +{} +SystemSemaphore::~SystemSemaphore () +{ + delete m_priv; +} +void +SystemSemaphore::post (void) +{ + m_priv->post (); +} +void +SystemSemaphore::post (uint32_t n) +{ + m_priv->post (n); +} +void +SystemSemaphore::wait (void) +{ + m_priv->wait (); +} +void +SystemSemaphore::wait (uint32_t n) +{ + m_priv->wait (n); +} + + + +}; // namespace yans diff --git a/src/core/win32-system-thread.cc b/src/core/win32-system-thread.cc new file mode 100644 index 000000000..1062c7d9d --- /dev/null +++ b/src/core/win32-system-thread.cc @@ -0,0 +1,66 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "system-thread.h" +#include +#include + +namespace yans { + +class SystemThreadPrivate { +public: + SystemThreadPrivate (SystemThread *thread); + ~SystemThreadPrivate (); +private: + static void *thread_run (void *thread); + SystemThread *m_thread; + HANDLE m_system_thread; +}; + +SystemThreadPrivate::SystemThreadPrivate (SystemThread *thread) + : m_thread (thread) +{ + m_system_thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE)SystemThreadPrivate::thread_run, + this, 0, 0); + assert (m_system_thread != NULL); +} +SystemThreadPrivate::~SystemThreadPrivate () +{} +void * +SystemThreadPrivate::thread_run (void *thread) +{ + SystemThreadPrivate *self = reinterpret_cast (thread); + self->m_thread->real_run (); + return thread; +} + +SystemThread::SystemThread () + : m_priv (new SystemThreadPrivate (this)) +{} + +SystemThread::~SystemThread () +{ + delete m_priv; +} + +}; // namespace yans + diff --git a/src/core/win32-wall-clock-ms.cc b/src/core/win32-wall-clock-ms.cc new file mode 100644 index 000000000..e783dafc8 --- /dev/null +++ b/src/core/win32-wall-clock-ms.cc @@ -0,0 +1,65 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "wall-clock-ms.h" + +namespace yans { + +class WallClockMsPrivate { +public: + void start (void); + unsigned long long end (void); +private: +}; + +void +WallClockMsPrivate::start (void) +{ +} + +unsigned long long +WallClockMsPrivate::end (void) +{ + return 0; +} + +WallClockMs::WallClockMs () + : m_priv (new WallClockMsPrivate ()) +{} + +WallClockMs::~WallClockMs () +{ + delete m_priv; + m_priv = 0; +} + +void +WallClockMs::start (void) +{ + m_priv->start (); +} +unsigned long long +WallClockMs::end (void) +{ + return m_priv->end (); +} + +}; // namespace yans diff --git a/src/simulator/event-impl.cc b/src/simulator/event-impl.cc new file mode 100644 index 000000000..708f063d4 --- /dev/null +++ b/src/simulator/event-impl.cc @@ -0,0 +1,67 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "event-impl.h" + + +namespace yans { + + +EventImpl::~EventImpl () +{} + +EventImpl::EventImpl () + : m_id (0), + m_count (1), + m_cancel (0), + m_running (1) +{} +void +EventImpl::invoke (void) +{ + if (m_cancel == 0) { + notify (); + } + m_running = 0; +} +void +EventImpl::set_tag (void *tag) +{ + m_id = tag; +} +void * +EventImpl::get_tag (void) const +{ + return m_id; +} +void +EventImpl::cancel (void) +{ + m_cancel = 1; + m_running = 0; +} +bool +EventImpl::is_running (void) +{ + return (m_running == 1); +} + +}; // namespace yans diff --git a/src/simulator/event-impl.h b/src/simulator/event-impl.h new file mode 100644 index 000000000..b781606c5 --- /dev/null +++ b/src/simulator/event-impl.h @@ -0,0 +1,49 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#ifndef EVENT_IMPL_H +#define EVENT_IMPL_H + +#include + +namespace yans { + +class EventImpl { +public: + EventImpl (); + virtual ~EventImpl () = 0; + void invoke (void); + void set_tag (void *tag); + void *get_tag (void) const; + void cancel (void); + bool is_running (void); +protected: + virtual void notify (void) = 0; +private: + friend class Event; + void *m_id; + uint32_t m_count; + uint32_t m_cancel : 1; + uint32_t m_running : 1; +}; + +}; // namespace yans + +#endif /* EVENT_IMPL_H */ diff --git a/src/simulator/event-tcc-test.cc b/src/simulator/event-tcc-test.cc new file mode 100644 index 000000000..c0dd648b8 --- /dev/null +++ b/src/simulator/event-tcc-test.cc @@ -0,0 +1,110 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "event.tcc" +#include "yans/test.h" + +#ifdef RUN_SELF_TESTS + +#define ENSURE(got,expected) \ +if (got != expected) { \ + g_error = true; \ +} + +namespace { +bool g_error = false; + +void null_cb (void) +{} +void one_cb (int a) +{ + ENSURE (a, 1); +} +void two_cb (int a,int b) +{ + ENSURE (a, 1); + ENSURE (b, 2); +} +void three_cb (int a,int b,int c) +{ + ENSURE (a, 1); + ENSURE (b, 2); + ENSURE (c, 3); +} +void four_cb (int a,int b,int c,int d) +{ + ENSURE (a, 1); + ENSURE (b, 2); + ENSURE (c, 3); + ENSURE (d, 4); +} +void five_cb (int a,int b,int c,int d,int e) +{ + ENSURE (a, 1); + ENSURE (b, 2); + ENSURE (c, 3); + ENSURE (d, 4); + ENSURE (e, 5); +} + +}; + +namespace yans { +class EventTest : public Test { +public: + EventTest (); + virtual bool run_tests (void); +}; + +EventTest::EventTest () + : Test ("Event") +{} + +bool +EventTest::run_tests (void) +{ + Event ev; + + ev = yans::make_event (&null_cb); + ev (); + ev = yans::make_event (&one_cb, 1); + ev (); + ev = yans::make_event (&two_cb, 1, 2); + ev (); + ev = yans::make_event (&three_cb, 1, 2, 3); + ev (); + ev = yans::make_event (&four_cb, 1, 2, 3, 4); + ev (); + ev = yans::make_event (&five_cb, 1, 2, 3, 4, 5); + ev (); + + if (g_error) { + return false; + } + return true; +} + +static EventTest g_test; + +}; + + + +#endif /* RUN_SELF_TESTS */ diff --git a/src/simulator/event-tcc.cc b/src/simulator/event-tcc.cc new file mode 100644 index 000000000..f953297c8 --- /dev/null +++ b/src/simulator/event-tcc.cc @@ -0,0 +1,47 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ +#include "event-impl.h" +#include "event.h" + +namespace yans { + +class EventFunctionImpl0 : public EventImpl { +public: + typedef void (*F)(void); + + EventFunctionImpl0 (F function) + : m_function (function) + {} + virtual ~EventFunctionImpl0 () {} +private: + virtual void notify (void) { + (*m_function) (); + } +private: + F m_function; +}; + +Event make_event(void (*f) (void)) +{ + return Event (new EventFunctionImpl0 (f)); +} + +}; // namespace yans diff --git a/src/simulator/event.h b/src/simulator/event.h new file mode 100644 index 000000000..5dcd4ac31 --- /dev/null +++ b/src/simulator/event.h @@ -0,0 +1,140 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef EVENT_H +#define EVENT_H + +#include +#include "event-impl.h" + +namespace yans { + + +class EventImpl; +/** + * \brief Simulation events. + * + * The Event class has POD semantics: it can and should + * be passed around by value. The Event class is a mere + * wrapper around the EventImpl class and performs + * memory management of EventImpl object instances. + * + * While users could create Events by instanciating + * subclasses of the EventImpl class and storing them + * in an Event instance, they are advised to use the + * template functions \ref make_event instead. + */ +class Event { +public: + Event () + : m_impl (0) + {} + Event (EventImpl *impl) + : m_impl (impl) + {} + Event (Event const &o) + : m_impl (o.m_impl) + { + if (m_impl != 0) { + m_impl->m_count++; + } + } + ~Event () + { + if (m_impl != 0) { + m_impl->m_count--; + if (m_impl->m_count == 0) { + delete m_impl; + } + } + m_impl = 0; + } + Event &operator = (Event const&o) + { + if (m_impl != 0) { + m_impl->m_count--; + if (m_impl->m_count == 0) { + delete m_impl; + } + } + m_impl = o.m_impl; + if (m_impl != 0) { + m_impl->m_count++; + } + return *this; + } + void operator () (void) + { + m_impl->invoke (); + } + /** + * Cancel an event. This operation has O(1) + * complexity since it merely sets a "cancel" bit + * to on and does not remove the Event from the + * scheduler's event list. When the event expires, + * the scheduler checks this cancel bit and, if set, + * does not execute the event. + */ + void cancel (void) + { + if (m_impl != 0) { + m_impl->cancel (); + } + } + /** + * Return true if the event is in RUNNING state. + * Return false otherwise. + * + * An Event is created in RUNNING state and switches + * to NON_RUNNING state upon one of: + * - cancel bit is set to on + * - Event execution is completed. + * It is important to note that an event is in RUNNING + * state while being executed. + */ + bool is_running (void) + { + if (m_impl != 0 && m_impl->is_running ()) { + return true; + } else { + return false; + } + } + +private: + friend class SchedulerHeap; + friend class SchedulerList; + friend class SchedulerMap; + void set_tag (void *tag) + { + return m_impl->set_tag (tag); + } + void *get_tag (void) const + { + return m_impl->get_tag (); + } + + EventImpl *m_impl; +}; + +}; // namespace yans + +#endif /* EVENT_H */ diff --git a/src/simulator/event.tcc b/src/simulator/event.tcc new file mode 100644 index 000000000..0a1742931 --- /dev/null +++ b/src/simulator/event.tcc @@ -0,0 +1,454 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef EVENT_TCC +#define EVENT_TCC + +#include "event.h" +#include "event-impl.h" + +/** + * yans namespace + */ +namespace yans { + +/** + * \defgroup make_event make_event + * + * Every make_event template function returns a newly-created Event + * which holds a pointer to a special subclass of the EventImpl + * base class. Each of these subclasses holds information about which + * function or method to call and which parameters must be forwarded + * to this function or method. + * + * Sample code is shown below: + * \include samples/main-event.cc + */ + +template +class EventMemberImpl0 : public EventImpl { +public: + typedef void (T::*F)(void); + + EventMemberImpl0 (T *obj, F function) + : m_obj (obj), + m_function (function) + {} + virtual ~EventMemberImpl0 () {} +private: + virtual void notify (void) { + (m_obj->*m_function) (); + } + T* m_obj; + F m_function; +}; + +template +class EventMemberImpl1 : public EventImpl { +public: + typedef void (T::*F)(T1); + + EventMemberImpl1 (T *obj, F function, T1 a1) + : m_obj (obj), + m_function (function), + m_a1 (a1) + { } + virtual ~EventMemberImpl1 () {} +private: + virtual void notify (void) { + (m_obj->*m_function) (m_a1); + } + T* m_obj; + F m_function; + T1 m_a1; +}; + +template +class EventMemberImpl2 : public EventImpl { +public: + typedef void (T::*F)(T1, T2); + + EventMemberImpl2 (T *obj, F function, T1 a1, T2 a2) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2) + { } + virtual ~EventMemberImpl2 () {} +private: + virtual void notify (void) { + (m_obj->*m_function) (m_a1, m_a2); + } + T* m_obj; + F m_function; + T1 m_a1; + T2 m_a2; +}; + +template +class EventMemberImpl3 : public EventImpl { +public: + typedef void (T::*F)(T1, T2, T3); + + EventMemberImpl3 (T *obj, F function, T1 a1, T2 a2, T3 a3) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3) + { } + virtual ~EventMemberImpl3 () {} +private: + virtual void notify (void) { + (m_obj->*m_function) (m_a1, m_a2, m_a3); + } + T* m_obj; + F m_function; + T1 m_a1; + T2 m_a2; + T3 m_a3; +}; + +template +class EventMemberImpl4 : public EventImpl { +public: + typedef void (T::*F)(T1, T2, T3, T4); + + EventMemberImpl4 (T *obj, F function, T1 a1, T2 a2, T3 a3, T4 a4) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4) + { } + virtual ~EventMemberImpl4 () {} +private: + virtual void notify (void) { + (m_obj->*m_function) (m_a1, m_a2, m_a3, m_a4); + } + T* m_obj; + F m_function; + T1 m_a1; + T2 m_a2; + T3 m_a3; + T4 m_a4; +}; + +template +class EventMemberImpl5 : public EventImpl { +public: + typedef void (T::*F)(T1, T2, T3, T4, T5); + + EventMemberImpl5 (T *obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + : m_obj (obj), + m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4), + m_a5 (a5) + { } + virtual ~EventMemberImpl5 () {} +private: + virtual void notify (void) { + (m_obj->*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); + } + T* m_obj; + F m_function; + T1 m_a1; + T2 m_a2; + T3 m_a3; + T4 m_a4; + T5 m_a5; +}; + +/** + * \ingroup make_event + * \param f class method member pointer + * \param t class instance + * \return a wrapper Event + * Build Events for class method members which take no arguments. + */ +template +Event make_event(void (T::*f) (void), T* t) { + return Event (new EventMemberImpl0(t, f)); +} +/** + * \ingroup make_event + * \param f class method member pointer + * \param t class instance + * \param a1 first argument to pass to the target method when the event expires + * \return a wrapper Event + * Build Events for class method members which take only one argument + */ +template +Event make_event(void (T::*f) (T1), T* t, T1 a1) { + return Event (new EventMemberImpl1(t, f, a1)); +} +/** + * \ingroup make_event + * \param f class method member pointer + * \param t class instance + * \param a1 first argument to pass to the target method when the event expires + * \param a2 second argument to pass to the target method when the event expires + * \return a wrapper Event + * Build Events for class method members which take two arguments + */ +template +Event make_event(void (T::*f) (T1, T2), T* t, T1 a1, T2 a2) { + return Event (new EventMemberImpl2(t, f, a1, a2)); +} +/** + * \ingroup make_event + * \param f class method member pointer + * \param t class instance + * \param a1 first argument to pass to the target method when the event expires + * \param a2 second argument to pass to the target method when the event expires + * \param a3 third argument to pass to the target method when the event expires + * \return a wrapper Event + * Build Events for class method members which take three arguments + */ +template +Event make_event(void (T::*f) (T1, T2, T3), T* t, T1 a1, T2 a2, T3 a3) { + return Event (new EventMemberImpl3(t, f, a1, a2, a3)); +} +/** + * \ingroup make_event + * \param f class method member pointer + * \param t class instance + * \param a1 first argument to pass to the target method when the event expires + * \param a2 second argument to pass to the target method when the event expires + * \param a3 third argument to pass to the target method when the event expires + * \param a4 fourth argument to pass to the target method when the event expires + * \return a wrapper Event + * Build Events for class method members which take four arguments + */ +template +Event make_event(void (T::*f) (T1, T2, T3, T4), T* t, T1 a1, T2 a2, T3 a3, T4 a4) { + return Event (new EventMemberImpl4(t, f, a1, a2, a3, a4)); +} +/** + * \ingroup make_event + * \param f class method member pointer + * \param t class instance + * \param a1 first argument to pass to the target method when the event expires + * \param a2 second argument to pass to the target method when the event expires + * \param a3 third argument to pass to the target method when the event expires + * \param a4 fourth argument to pass to the target method when the event expires + * \param a5 fifth argument to pass to the target method when the event expires + * \return a wrapper Event + * Build Events for class method members which take five arguments. + */ +template +Event make_event(void (T::*f) (T1, T2, T3, T4, T5), T* t, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { + return Event (new EventMemberImpl5(t, f, a1, a2, a3, a4, a5)); +} + +template +class EventFunctionImpl1 : public EventImpl { +public: + typedef void (*F)(T1); + + EventFunctionImpl1 (F function, T1 a1) + : m_function (function), + m_a1 (a1) + { } + virtual ~EventFunctionImpl1 () {} +private: + virtual void notify (void) { + (*m_function) (m_a1); + } + F m_function; + T1 m_a1; +}; + +template +class EventFunctionImpl2 : public EventImpl { +public: + typedef void (*F)(T1, T2); + + EventFunctionImpl2 (F function, T1 a1, T2 a2) + : m_function (function), + m_a1 (a1), + m_a2 (a2) + { } + virtual ~EventFunctionImpl2 () {} +private: + virtual void notify (void) { + (*m_function) (m_a1, m_a2); + } + F m_function; + T1 m_a1; + T2 m_a2; +}; + +template +class EventFunctionImpl3 : public EventImpl { +public: + typedef void (*F)(T1, T2, T3); + + EventFunctionImpl3 (F function, T1 a1, T2 a2, T3 a3) + : m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3) + { } + virtual ~EventFunctionImpl3 () {} +private: + virtual void notify (void) { + (*m_function) (m_a1, m_a2, m_a3); + } + F m_function; + T1 m_a1; + T2 m_a2; + T3 m_a3; +}; + +template +class EventFunctionImpl4 : public EventImpl { +public: + typedef void (*F)(T1, T2, T3, T4); + + EventFunctionImpl4 (F function, T1 a1, T2 a2, T3 a3, T4 a4) + : m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4) + { } + virtual ~EventFunctionImpl4 () {} +private: + virtual void notify (void) { + (*m_function) (m_a1, m_a2, m_a3, m_a4); + } + F m_function; + T1 m_a1; + T2 m_a2; + T3 m_a3; + T4 m_a4; +}; + +template +class EventFunctionImpl5 : public EventImpl { +public: + typedef void (*F)(T1, T2, T3, T4, T5); + + EventFunctionImpl5 (F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + : m_function (function), + m_a1 (a1), + m_a2 (a2), + m_a3 (a3), + m_a4 (a4), + m_a5 (a5) + { } + virtual ~EventFunctionImpl5 () {} +private: + virtual void notify (void) { + (*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5); + } + F m_function; + T1 m_a1; + T2 m_a2; + T3 m_a3; + T4 m_a4; + T5 m_a5; +}; + + +/** + * \ingroup make_event + * \param f function pointer + * \return a wrapper Event + * Build Events for function pointers which take no arguments + */ +Event make_event(void (*f) (void)); + +/** + * \ingroup make_event + * \param f function pointer + * \param a1 first argument to pass to the target function when the event expires + * \return a wrapper Event + * Build Events for function pointers which take one argument + */ +template +Event make_event(void (*f) (T1), T1 a1) { + return Event (new EventFunctionImpl1(f, a1)); +} +/** + * \ingroup make_event + * \param f function pointer + * \param a1 first argument to pass to the target function when the event expires + * \param a2 second argument to pass to the target function when the event expires + * \return a wrapper Event + * Build Events for function pointers which take two argument + */ +template +Event make_event(void (*f) (T1, T2), T1 a1, T2 a2) { + return Event (new EventFunctionImpl2(f, a1, a2)); +} +/** + * \ingroup make_event + * \param f function pointer + * \param a1 first argument to pass to the target function when the event expires + * \param a2 second argument to pass to the target function when the event expires + * \param a3 third argument to pass to the target function when the event expires + * \return a wrapper Event + * Build Events for function pointers which take three argument + */ +template +Event make_event(void (*f) (T1, T2, T3), T1 a1, T2 a2, T3 a3) { + return Event (new EventFunctionImpl3(f, a1, a2, a3)); +} +/** + * \ingroup make_event + * \param f function pointer + * \param a1 first argument to pass to the target function when the event expires + * \param a2 second argument to pass to the target function when the event expires + * \param a3 third argument to pass to the target function when the event expires + * \param a4 fourth argument to pass to the target function when the event expires + * \return a wrapper Event + * Build Events for function pointers which take four argument + */ +template +Event make_event(void (*f) (T1, T2, T3, T4), T1 a1, T2 a2, T3 a3, T4 a4) { + return Event (new EventFunctionImpl4(f, a1, a2, a3, a4)); +} +/** + * \ingroup make_event + * \param f function pointer + * \param a1 first argument to pass to the target function when the event expires + * \param a2 second argument to pass to the target function when the event expires + * \param a3 third argument to pass to the target function when the event expires + * \param a4 fourth argument to pass to the target function when the event expires + * \param a5 fifth argument to pass to the target function when the event expires + * \return a wrapper Event + * Build Events for function pointers which take five argument + */ +template +Event make_event(void (*f) (T1, T2, T3, T4, T5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { + return Event (new EventFunctionImpl5(f, a1, a2, a3, a4, a5)); +} + + +}; // namespace yans + +#endif /* EVENT_TCC */ diff --git a/src/simulator/scheduler-heap.cc b/src/simulator/scheduler-heap.cc new file mode 100644 index 000000000..6addb02e1 --- /dev/null +++ b/src/simulator/scheduler-heap.cc @@ -0,0 +1,243 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * Copyright (c) 2005 Mathieu Lacage + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + * + * This code started as a c++ translation of a java-based code written in 2005 + * to implement a heap sort. Which explains the Copyright Mathieu Lacage at the + * top of this file. + * + * What is smart about this code ? + * - it does not use the index 0 in the array to avoid having to convert + * C-style array indexes (which start at zero) and heap-style indexes + * (which start at 1). This is why _all_ indexes start at 1, and that + * the index of the root is 1. + * - It uses a slightly non-standard while loop for top-down heapify + * to move one if statement out of the loop. + */ + +#include "scheduler-heap.h" +#include "event.h" +#include + +#define noTRACE_HEAP 1 + +#ifdef TRACE_HEAP +#include +# define TRACE(x) \ +std::cout << "HEAP TRACE " << x << std::endl; +#else /* TRACE_HEAP */ +# define TRACE(format,...) +#endif /* TRACE_HEAP */ + + + + +namespace yans { + +SchedulerHeap::SchedulerHeap () +{ + // we purposedly waste an item at the start of + // the array to make sure the indexes in the + // array start at one. + Scheduler::EventKey empty_key = {0,0}; + m_heap.push_back (std::make_pair ((Event )0, empty_key)); +} + +SchedulerHeap::~SchedulerHeap () +{} + + +void +SchedulerHeap::store_in_event (Event ev, uint32_t index) const +{ + ev.set_tag ((void *)index); +} +uint32_t +SchedulerHeap::get_from_event (Event const ev) const +{ + return (uint32_t)ev.get_tag (); +} + + +uint32_t +SchedulerHeap::parent (uint32_t id) const +{ + return id / 2; +} +uint32_t +SchedulerHeap::sibling (uint32_t id) const +{ + return id + 1; +} +uint32_t +SchedulerHeap::left_child (uint32_t id) const +{ + return id * 2; +} +uint32_t +SchedulerHeap::right_child (uint32_t id) const +{ + return id * 2 + 1; +} + +uint32_t +SchedulerHeap::root (void) const +{ + return 1; +} + +bool +SchedulerHeap::is_root (uint32_t id) const +{ + return (id == root ())?true:false; +} + +uint32_t +SchedulerHeap::last (void) const +{ + return m_heap.size () - 1; +} + + +bool +SchedulerHeap::is_bottom (uint32_t id) const +{ + return (id >= m_heap.size ())?true:false; +} + +void +SchedulerHeap::exch (uint32_t a, uint32_t b) +{ + assert (b < m_heap.size () && a < m_heap.size ()); + TRACE ("exch " << a << ", " << b); +#if 1 + std::swap (m_heap[a].second, m_heap[b].second); + std::swap (m_heap[a].first.m_impl, m_heap[b].first.m_impl); +#else + std::pair tmp (m_heap[a]); + m_heap[a] = m_heap[b]; + m_heap[b] = tmp; +#endif + store_in_event (m_heap[a].first, a); + store_in_event (m_heap[b].first, b); +} + +bool +SchedulerHeap::is_less (uint32_t a, uint32_t b) +{ + Scheduler::EventKeyCompare compare; + return compare (m_heap[a].second, m_heap[b].second); +} + +uint32_t +SchedulerHeap::smallest (uint32_t a, uint32_t b) +{ + return is_less (a,b)?a:b; +} + +bool +SchedulerHeap::is_empty (void) const +{ + return (m_heap.size () == 1)?true:false; +} + +void +SchedulerHeap::bottom_up (void) +{ + uint32_t index = last (); + while (!is_root (index) && + is_less (index, parent (index))) { + exch(index, parent (index)); + index = parent (index); + } +} + +void +SchedulerHeap::top_down (void) +{ + uint32_t index = root (); + uint32_t right = right_child (index); + while (!is_bottom (right)) { + uint32_t left = left_child (index); + uint32_t tmp = smallest (left, right); + if (is_less (index, tmp)) { + return; + } + exch (index, tmp); + index = tmp; + right = right_child (index); + } + if (is_bottom (index)) { + return; + } + assert (!is_bottom (index)); + uint32_t left = left_child (index); + if (is_bottom (left)) { + return; + } + if (is_less (index, left)) { + return; + } + exch (index, left); +} + + +Event +SchedulerHeap::insert (Event event, Scheduler::EventKey key) +{ + m_heap.push_back (std::make_pair (event, key)); + store_in_event (event, last ()); + bottom_up (); + return event; +} + +Event +SchedulerHeap::peek_next (void) const +{ + assert (!is_empty ()); + return m_heap[root ()].first; +} +Scheduler::EventKey +SchedulerHeap::peek_next_key (void) const +{ + assert (!is_empty ()); + return m_heap[root ()].second; +} +void +SchedulerHeap::remove_next (void) +{ + assert (!is_empty ()); + exch (root (), last ()); + m_heap.pop_back (); + top_down (); +} + +Scheduler::EventKey +SchedulerHeap::remove (Event const ev) +{ + uint32_t i = get_from_event (ev); + EventKey key = m_heap[i].second; + exch (i, last ()); + m_heap.pop_back (); + top_down (); + return key; +} + +}; // namespace yans diff --git a/src/simulator/scheduler-heap.h b/src/simulator/scheduler-heap.h new file mode 100644 index 000000000..a74b65cec --- /dev/null +++ b/src/simulator/scheduler-heap.h @@ -0,0 +1,71 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SCHEDULER_HEAP_H +#define SCHEDULER_HEAP_H + +#include "scheduler.h" +#include +#include + +namespace yans { + +class Event; +class EventHolder; + +class SchedulerHeap : public Scheduler { +public: + SchedulerHeap (); + virtual ~SchedulerHeap (); + + virtual Event insert (Event event, Scheduler::EventKey key); + virtual bool is_empty (void) const; + virtual Event peek_next (void) const; + virtual Scheduler::EventKey peek_next_key (void) const; + virtual void remove_next (void); + virtual Scheduler::EventKey remove (Event const ev); +private: + typedef std::vector > BinaryHeap; + inline void store_in_event (Event ev, uint32_t index) const; + uint32_t get_from_event (Event const ev) const; + + inline uint32_t parent (uint32_t id) const; + uint32_t sibling (uint32_t id) const; + inline uint32_t left_child (uint32_t id) const; + inline uint32_t right_child (uint32_t id) const; + inline uint32_t root (void) const; + uint32_t last (void) const; + inline bool is_root (uint32_t id) const; + inline bool is_bottom (uint32_t id) const; + inline bool is_less (uint32_t a, uint32_t b); + inline uint32_t smallest (uint32_t a, uint32_t b); + + inline void exch (uint32_t a, uint32_t b); + void bottom_up (void); + void top_down (void); + + BinaryHeap m_heap; +}; + +}; // namespace yans + + +#endif /* SCHEDULER_HEAP_H */ diff --git a/src/simulator/scheduler-list.cc b/src/simulator/scheduler-list.cc new file mode 100644 index 000000000..467874f02 --- /dev/null +++ b/src/simulator/scheduler-list.cc @@ -0,0 +1,107 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "scheduler-list.h" +#include "event.h" +#include +#include + +namespace yans { + +SchedulerList::SchedulerList () +{} +SchedulerList::~SchedulerList () +{} + +/* !! WARNING !! + * This is a very nasty piece of code but it really should work + * with pretty much any implementation of a std::list. + * it relies on the fact that a std::list<>::iterator has a single + * member variable, a pointer. + */ +void +SchedulerList::store_in_event (Event ev, EventsI i) +{ + assert (sizeof (i) <= sizeof (Event)); + void *tag; + strncpy ((char *)&(tag), (char *)&i, sizeof (void *)); + ev.set_tag (tag); +} +SchedulerList::EventsI +SchedulerList::get_from_event (Event const ev) +{ + SchedulerList::EventsI i; + assert (sizeof (i) <= sizeof (Event)); + void *tag = ev.get_tag (); + strncpy ((char *)&i, (char *)&(tag), sizeof (void *)); + return i; +} + + +Event +SchedulerList::insert (Event event, Scheduler::EventKey key) +{ + Scheduler::EventKeyCompare compare; + for (EventsI i = m_events.begin (); i != m_events.end (); i++) { + if (compare (key, i->second)) { + m_events.insert (i, std::make_pair (event, key)); + store_in_event (event, i); + return event; + } + } + m_events.push_back (std::make_pair (event, key)); + store_in_event (event, --(m_events.end ())); + return event; +} +bool +SchedulerList::is_empty (void) const +{ + return m_events.empty (); +} +Event +SchedulerList::peek_next (void) const +{ + assert (!is_empty ()); + return m_events.front ().first; +} +Scheduler::EventKey +SchedulerList::peek_next_key (void) const +{ + assert (!is_empty ()); + return m_events.front ().second; +} + +void +SchedulerList::remove_next (void) +{ + m_events.pop_front (); +} + +Scheduler::EventKey +SchedulerList::remove (Event const ev) +{ + EventsI i = get_from_event (ev); + EventKey key = (*i).second; + m_events.erase (get_from_event (ev)); + return key; +} + +}; // namespace yans diff --git a/src/simulator/scheduler-list.h b/src/simulator/scheduler-list.h new file mode 100644 index 000000000..e4af68981 --- /dev/null +++ b/src/simulator/scheduler-list.h @@ -0,0 +1,57 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SCHEDULER_LIST_H +#define SCHEDULER_LIST_H + +#include "scheduler.h" +#include +#include +#include + +namespace yans { + +class Event; + +class SchedulerList : public Scheduler { + public: + SchedulerList (); + virtual ~SchedulerList (); + + virtual Event insert (Event event, EventKey key); + virtual bool is_empty (void) const; + virtual Event peek_next (void) const; + virtual Scheduler::EventKey peek_next_key (void) const; + virtual void remove_next (void); + virtual Scheduler::EventKey remove (Event const ev); + + private: + typedef std::list > Events; + typedef std::list >::iterator EventsI; + void store_in_event (Event ev, EventsI i); + EventsI get_from_event (Event const ev); + Events m_events; +}; + +}; // namespace yans + + +#endif /* SCHEDULER_LIST_H */ diff --git a/src/simulator/scheduler-map.cc b/src/simulator/scheduler-map.cc new file mode 100644 index 000000000..b78243bf9 --- /dev/null +++ b/src/simulator/scheduler-map.cc @@ -0,0 +1,112 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + * The idea to use a std c++ map came from GTNetS + */ + +#include "scheduler-map.h" +#include "event.h" +#include + +#define noTRACE_MAP 1 + +#ifdef TRACE_MAP +#include +# define TRACE(x) \ +std::cout << "MAP TRACE " << x << std::endl; +#else /* TRACE_MAP */ +# define TRACE(format,...) +#endif /* TRACE_MAP */ + + +namespace yans { + + +SchedulerMap::SchedulerMap () +{} +SchedulerMap::~SchedulerMap () +{} + + +void +SchedulerMap::store_in_event (Event ev, EventMapI i) const +{ + void *tag; + memcpy (&(tag), &i, sizeof (tag)); + ev.set_tag (tag); +} +SchedulerMap::EventMapI +SchedulerMap::get_from_event (Event const ev) const +{ + EventMapI i; + void *tag = ev.get_tag (); + memcpy (&i, &(tag), sizeof (i)); + return i; +} + +Event +SchedulerMap::insert (Event event, Scheduler::EventKey key) +{ + std::pair result = m_list.insert (std::make_pair (key, event)); + assert (result.second); + store_in_event (event, result.first); + return event; +} + +bool +SchedulerMap::is_empty (void) const +{ + return m_list.empty (); +} + +Event +SchedulerMap::peek_next (void) const +{ + assert (!is_empty ()); + EventMapCI i = m_list.begin (); + assert (i != m_list.end ()); + return (*i).second; +} +Scheduler::EventKey +SchedulerMap::peek_next_key (void) const +{ + assert (!is_empty ()); + EventMapCI i = m_list.begin (); + assert (i != m_list.end ()); + return (*i).first; +} +void +SchedulerMap::remove_next (void) +{ + assert (!is_empty ()); + m_list.erase (m_list.begin ()); +} + +Scheduler::EventKey +SchedulerMap::remove (Event const ev) +{ + assert (!is_empty ()); + EventMapI i = get_from_event (ev); + EventKey key = (*i).first; + m_list.erase (i); + return key; +} + + +}; // namespace yans diff --git a/src/simulator/scheduler-map.h b/src/simulator/scheduler-map.h new file mode 100644 index 000000000..3659ec077 --- /dev/null +++ b/src/simulator/scheduler-map.h @@ -0,0 +1,59 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SCHEDULER_MAP_H +#define SCHEDULER_MAP_H + +#include "scheduler.h" +#include +#include +#include + +namespace yans { + +class SchedulerMap : public Scheduler { +public: + SchedulerMap (); + virtual ~SchedulerMap (); + + virtual Event insert (Event event, Scheduler::EventKey key); + virtual bool is_empty (void) const; + virtual Event peek_next (void) const; + virtual Scheduler::EventKey peek_next_key (void) const; + virtual void remove_next (void); + virtual Scheduler::EventKey remove (Event const ev); +private: + typedef std::map EventMap; + typedef std::map::iterator EventMapI; + typedef std::map::const_iterator EventMapCI; + + void store_in_event (Event ev, EventMapI i) const; + EventMapI get_from_event (Event const ev) const; + + + EventMap m_list; + uint32_t m_uid; +}; + +}; // namespace yans + + +#endif /* SCHEDULER_MAP_H */ diff --git a/src/simulator/scheduler.cc b/src/simulator/scheduler.cc new file mode 100644 index 000000000..c2f8fa971 --- /dev/null +++ b/src/simulator/scheduler.cc @@ -0,0 +1,46 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "scheduler.h" +#include + + +yans::Scheduler::~Scheduler () +{} + +/* Note the invariants which this function must provide: + * - irreflexibility: f (x,x) is false) + * - antisymmetry: f(x,y) = !f(y,x) + * - transitivity: f(x,y) and f(y,z) => f(x,z) + */ +bool +yans::Scheduler::EventKeyCompare::operator () (struct EventKey a, struct EventKey b) +{ + assert (a.m_uid != b.m_uid); + if (a.m_time < b.m_time) { + return true; + } else if (a.m_time == b.m_time && a.m_uid < b.m_uid) { + return true; + } else { + return false; + } +} + diff --git a/src/simulator/scheduler.h b/src/simulator/scheduler.h new file mode 100644 index 000000000..945ca4121 --- /dev/null +++ b/src/simulator/scheduler.h @@ -0,0 +1,54 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SCHEDULER_H +#define SCHEDULER_H + +#include +#include "event.h" + +namespace yans { + +class Scheduler { + public: + struct EventKey { + uint64_t m_time; + uint32_t m_uid; + }; + class EventKeyCompare { + public: + bool operator () (struct EventKey a, struct EventKey b); + }; + + virtual ~Scheduler () = 0; + virtual Event insert (Event event, EventKey key) = 0; + virtual bool is_empty (void) const = 0; + virtual Event peek_next (void) const = 0; + virtual EventKey peek_next_key (void) const = 0; + virtual void remove_next (void) = 0; + virtual EventKey remove (Event const ev) = 0; + +}; + +}; // namespace yans + + +#endif /* SCHEDULER_H */ diff --git a/src/simulator/simulator.cc b/src/simulator/simulator.cc new file mode 100644 index 000000000..73a774ec6 --- /dev/null +++ b/src/simulator/simulator.cc @@ -0,0 +1,544 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005,2006 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#include "simulator.h" +#include "scheduler.h" +#include "event.h" +#include "event.tcc" +#include "yans/system-semaphore.h" + +#include +#include +#include +#include +#include +#include + +#define noTRACE_SIMU 1 + +#ifdef TRACE_SIMU +#include +# define TRACE(x) \ +std::cout << "SIMU TRACE " << Simulator::now_s () << " " << x << std::endl; +# define TRACE_S(x) \ +std::cout << "SIMU TRACE " << x << std::endl; +#else /* TRACE_SIMU */ +# define TRACE(format,...) +# define TRACE_S(format,...) +#endif /* TRACE_SIMU */ + + +namespace yans { + +class ParallelSimulatorQueuePrivate { +public: + ParallelSimulatorQueuePrivate (SimulatorPrivate *priv); + ~ParallelSimulatorQueuePrivate (); + void set_queue (ParallelSimulatorQueue *queue); + void schedule_abs_us (Event ev, uint64_t at); + void send_null_message (void); +private: + void remove_event (Event ev); + uint32_t m_n; + SimulatorPrivate *m_simulator; + ParallelSimulatorQueue *m_queue; +}; + +class SimulatorPrivate { +public: + SimulatorPrivate (Scheduler *events); + ~SimulatorPrivate (); + + void enable_log_to (char const *filename); + + void add_queue (ParallelSimulatorQueuePrivate *queue); + void notify_queue_not_empty (void); + void notify_queue_empty (void); + void wait_until_no_queue_empty (void); + bool is_parallel (void); + + bool is_finished (void) const; + uint64_t next_us (void) const; + void run_serial (void); + void run_parallel (void); + void stop (void); + void stop_at_us (uint64_t at); + Event schedule_rel_us (Event event, uint64_t delta); + Event schedule_rel_s (Event event, double delta); + Event schedule_abs_us (Event event, uint64_t time); + Event schedule_abs_s (Event event, double time); + Event remove (Event const ev); + uint64_t now_us (void); + double now_s (void); + void schedule_now (Event event); + void schedule_destroy (Event event); + +private: + void process_one_event (void); + + typedef std::list > Events; + typedef std::vector Queues; + typedef std::vector::iterator QueuesI; + Events m_destroy; + uint64_t m_stop_at; + bool m_stop; + Scheduler *m_events; + uint32_t m_uid; + uint32_t m_current_uid; + uint64_t m_current_us; + std::ofstream m_log; + std::ifstream m_input_log; + bool m_log_enable; + uint32_t m_n_full_queues; + uint32_t m_n_queues; + SystemSemaphore *m_all_queues; + Queues m_queues; +}; + + +ParallelSimulatorQueuePrivate::ParallelSimulatorQueuePrivate (SimulatorPrivate *simulator) + : m_simulator (simulator) +{} +ParallelSimulatorQueuePrivate::~ParallelSimulatorQueuePrivate () +{} +void +ParallelSimulatorQueuePrivate::schedule_abs_us (Event ev, uint64_t at) +{ + m_n++; + if (m_n == 1) { + m_simulator->notify_queue_not_empty (); + } + m_simulator->schedule_abs_us (make_event (&ParallelSimulatorQueuePrivate::remove_event, this, ev), at); +} +void +ParallelSimulatorQueuePrivate::remove_event (Event ev) +{ + m_n--; + if (m_n == 0) { + m_simulator->notify_queue_empty (); + } + ev (); +} + +void +ParallelSimulatorQueuePrivate::set_queue (ParallelSimulatorQueue *queue) +{ + m_queue = queue; +} + +void +ParallelSimulatorQueuePrivate::send_null_message (void) +{ + m_queue->send_null_message (); +} + + + + +SimulatorPrivate::SimulatorPrivate (Scheduler *events) +{ + m_stop = false; + m_stop_at = 0; + m_events = events; + m_uid = 0; + m_log_enable = false; + m_current_us = 0; + m_all_queues = new SystemSemaphore (0); + m_n_queues = 0; + m_n_full_queues = 0; +} + +SimulatorPrivate::~SimulatorPrivate () +{ + while (!m_destroy.empty ()) { + Event ev = m_destroy.front ().first; + m_destroy.pop_front (); + TRACE ("handle destroy " << ev); + ev (); + } + delete m_events; + m_events = (Scheduler *)0xdeadbeaf; + delete m_all_queues; + m_queues.erase (m_queues.begin (), m_queues.end ()); +} + +bool +SimulatorPrivate::is_parallel (void) +{ + return (m_n_queues > 0); +} + +void +SimulatorPrivate::enable_log_to (char const *filename) +{ + m_log.open (filename); + m_log_enable = true; +} + +void +SimulatorPrivate::notify_queue_not_empty (void) +{ + m_n_full_queues++; + if (m_n_full_queues == m_n_queues) { + m_all_queues->post (); + } +} +void +SimulatorPrivate::notify_queue_empty (void) +{ + m_n_full_queues--; +} +void +SimulatorPrivate::wait_until_no_queue_empty (void) +{ + while (m_n_full_queues < m_n_queues) { + m_all_queues->wait (); + } +} + +void +SimulatorPrivate::add_queue (ParallelSimulatorQueuePrivate *queue) +{ + m_n_queues++; + m_queues.push_back (queue); +} + +void +SimulatorPrivate::process_one_event (void) +{ + Event next_ev = m_events->peek_next (); + Scheduler::EventKey next_key = m_events->peek_next_key (); + m_events->remove_next (); + TRACE ("handle " << next_ev); + m_current_us = next_key.m_time; + m_current_uid = next_key.m_uid; + if (m_log_enable) { + m_log << "e "<is_empty (); +} +uint64_t +SimulatorPrivate::next_us (void) const +{ + assert (!m_events->is_empty ()); + Scheduler::EventKey next_key = m_events->peek_next_key (); + return next_key.m_time; +} + + +void +SimulatorPrivate::run_serial (void) +{ + while (!m_events->is_empty () && !m_stop && + (m_stop_at == 0 || m_stop_at > next_us ())) { + process_one_event (); + } + m_log.close (); +} + +void +SimulatorPrivate::run_parallel (void) +{ + TRACE ("run parallel"); + while (!m_stop && + (m_stop_at == 0 || m_stop_at >= next_us ())) { + TRACE ("send null messages"); + for (QueuesI i = m_queues.begin (); i != m_queues.end (); i++) { + (*i)->send_null_message (); + } + TRACE ("sent null messages"); + wait_until_no_queue_empty (); + TRACE ("no queue empty"); + process_one_event(); + TRACE ("processed event"); + } + m_log.close (); + TRACE ("done run parallel"); +} + +void +SimulatorPrivate::stop (void) +{ + m_stop = true; +} +void +SimulatorPrivate::stop_at_us (uint64_t at) +{ + m_stop_at = at; +} +Event +SimulatorPrivate::schedule_rel_us (Event event, uint64_t delta) +{ + uint64_t current = now_us (); + return schedule_abs_us (event, current+delta); +} +Event +SimulatorPrivate::schedule_abs_us (Event event, uint64_t time) +{ + assert (time >= now_us ()); + Scheduler::EventKey key = {time, m_uid}; + if (m_log_enable) { + m_log << "i "<insert (event, key); +} +uint64_t +SimulatorPrivate::now_us (void) +{ + return m_current_us; +} +Event +SimulatorPrivate::schedule_rel_s (Event event, double delta) +{ + int64_t delta_us = (int64_t)(delta * 1000000.0); + uint64_t us = now_us () + delta_us; + return schedule_abs_us (event, us); +} +Event +SimulatorPrivate::schedule_abs_s (Event event, double time) +{ + int64_t us = (int64_t)(time * 1000000.0); + assert (us >= 0); + return schedule_abs_us (event, (uint64_t)us); +} +double +SimulatorPrivate::now_s (void) +{ + double us = m_current_us; + us /= 1000000; + return us; +} +void +SimulatorPrivate::schedule_now (Event event) +{ + schedule_abs_us (event, now_us ()); +} +void +SimulatorPrivate::schedule_destroy (Event event) +{ + m_destroy.push_back (std::make_pair (event, m_uid)); + if (m_log_enable) { + m_log << "id " << m_current_uid << " " << now_us () << " " + << m_uid << std::endl; + } + m_uid++; +} + +Event +SimulatorPrivate::remove (Event const ev) +{ + Scheduler::EventKey key = m_events->remove (ev); + if (m_log_enable) { + m_log << "r " << m_current_uid << " " << now_us () << " " + << key.m_uid << " " << key.m_time << std::endl; + } + return Event (ev); +} + + +}; // namespace yans + + +#include "scheduler-list.h" +#include "scheduler-heap.h" +#include "scheduler-map.h" + + +namespace yans { + +SimulatorPrivate *Simulator::m_priv = 0; +Simulator::ListType Simulator::m_list_type = LINKED_LIST; + +void Simulator::set_linked_list (void) +{ + m_list_type = LINKED_LIST; +} +void Simulator::set_binary_heap (void) +{ + m_list_type = BINARY_HEAP; +} +void Simulator::set_std_map (void) +{ + m_list_type = STD_MAP; +} +void Simulator::enable_log_to (char const *filename) +{ + get_priv ()->enable_log_to (filename); +} + + +SimulatorPrivate * +Simulator::get_priv (void) +{ + if (m_priv == 0) { + Scheduler *events; + switch (m_list_type) { + case LINKED_LIST: + events = new SchedulerList (); + break; + case BINARY_HEAP: + events = new SchedulerHeap (); + break; + case STD_MAP: + events = new SchedulerMap (); + break; + default: // not reached + events = 0; + assert (false); + break; + } + m_priv = new SimulatorPrivate (events); + } + TRACE_S ("priv " << m_priv); + return m_priv; +} + +void +Simulator::destroy (void) +{ + delete m_priv; + m_priv = 0; +} + +void +Simulator::add_parallel_queue (ParallelSimulatorQueue *queue) +{ + ParallelSimulatorQueuePrivate *priv = new ParallelSimulatorQueuePrivate (get_priv ()); + priv->set_queue (queue); + queue->set_priv (priv); + return get_priv ()->add_queue (priv); +} + +bool +Simulator::is_finished (void) +{ + return get_priv ()->is_finished (); +} +uint64_t +Simulator::next_us (void) +{ + return get_priv ()->next_us (); +} + + +void +Simulator::run (void) +{ + if (get_priv ()->is_parallel ()) { + get_priv ()->run_parallel (); + } else { + get_priv ()->run_serial (); + } +} +void +Simulator::stop (void) +{ + TRACE ("stop"); + get_priv ()->stop (); +} +void +Simulator::stop_at_us (uint64_t at) +{ + get_priv ()->stop_at_us (at); +} +Event +Simulator::schedule_rel_us (uint64_t delta, Event event) +{ + TRACE ("insert " << event << " in " << delta << "us"); + return get_priv ()->schedule_rel_us (event, delta); +} +Event +Simulator::schedule_abs_us (uint64_t time, Event event) +{ + TRACE ("insert " << event << " at " << time << "us"); + return get_priv ()->schedule_abs_us (event, time); +} +uint64_t +Simulator::now_us (void) +{ + return get_priv ()->now_us (); +} +Event +Simulator::schedule_rel_s (double delta, Event event) +{ + TRACE ("insert " << event << " in " << delta << "s"); + return get_priv ()->schedule_rel_s (event, delta); +} +Event +Simulator::schedule_abs_s (double time, Event event) +{ + TRACE ("insert " << event << " at " << time << "s"); + return get_priv ()->schedule_abs_s (event, time); +} +double +Simulator::now_s (void) +{ + return get_priv ()->now_s (); +} +void +Simulator::schedule_now (Event event) +{ + TRACE ("insert later " << event); + return get_priv ()->schedule_now (event); +} +void +Simulator::schedule_destroy (Event event) +{ + TRACE ("insert at destroy " << event); + return get_priv ()->schedule_destroy (event); +} + +Event +Simulator::remove (Event const ev) +{ + return get_priv ()->remove (ev); +} + +}; // namespace yans + + +namespace yans { + +ParallelSimulatorQueue::ParallelSimulatorQueue () +{} +ParallelSimulatorQueue::~ParallelSimulatorQueue () +{ + delete m_priv; +} +void +ParallelSimulatorQueue::schedule_abs_us (uint64_t at, Event ev) +{ + m_priv->schedule_abs_us (ev, at); +} +void +ParallelSimulatorQueue::set_priv (ParallelSimulatorQueuePrivate *priv) +{ + m_priv = priv; +} +}; diff --git a/src/simulator/simulator.h b/src/simulator/simulator.h new file mode 100644 index 000000000..4fb762bc6 --- /dev/null +++ b/src/simulator/simulator.h @@ -0,0 +1,231 @@ +/* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */ +/* + * Copyright (c) 2005 INRIA + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Mathieu Lacage + */ + +#ifndef SIMULATOR_H +#define SIMULATOR_H + +#include +#include "event.h" + +namespace yans { + +class SimulatorPrivate; +class ParallelSimulatorQueuePrivate; + +class ParallelSimulatorQueue { +public: + virtual ~ParallelSimulatorQueue () = 0; + void schedule_abs_us (uint64_t at, Event ev); +private: + friend class Simulator; + friend class ParallelSimulatorQueuePrivate; + + void set_priv (ParallelSimulatorQueuePrivate *priv); + virtual void send_null_message (void) = 0; + ParallelSimulatorQueuePrivate *m_priv; +protected: + ParallelSimulatorQueue (); +}; + +/** + * \brief Control the scheduling of simulation events. + * + * The internal simulation clock is maintained + * as a 64-bit integer in microsecond units. This means that it is + * not possible to specify event expiration times with anything better + * than microsecond accuracy. Events which whose expiration time is + * the same are scheduled in FIFO order: the first event inserted in the + * Scheduling queue is scheduled to expire first. + */ +class Simulator { +public: + /** + * Force the use of an event scheduler based on a linked-list. + * This method must be invoked before any other method exported + * by the Simulator class. + * - insert: O(n) + * - remove: O(1) + */ + static void set_linked_list (void); + /** + * Force the use of an event scheduler based on a binary heap. + * This method must be invoked before any other method exported + * by the Simulator class. + * - insert: O(log(n)) + * - remove: O(log(n)) + */ + static void set_binary_heap (void); + /** + * Force the use of an event scheduler based on a std::map. + * This method must be invoked before any other method exported + * by the Simulator class. + * - insert: O(log(n)) + * - remove: O(log(n)) + */ + static void set_std_map (void); + + /** + * Enable logging to the file identified by filename. If the file + * does not exist, it is created. If it exists, it is destroyed and + * re-created. Every scheduling event is logged to this file in a + * simple text format which can be read back by the event replay + * utility. This allows you to record the scheduling behavior of + * a simulation, and measure the exact overhead related to + * event scheduling with the event replay utility. It is also possible + * to compare the performance of every scheduling algorithms on this + * specific scheduling load. + * This method must be invoked before any call to Simulator::run + * @param filename the name of the file to log to + */ + static void enable_log_to (char const *filename); + + /** + * Every event scheduled by the Simulator::insert_at_destroy method is + * invoked. Then, we ensure that any memory allocated by the + * Simulator is freed. + * This method is typically invoked at the end of a simulation + * to avoid false-positive reports by a leak checker. + * After this method has been invoked, it is actually possible + * to restart a new simulation with a set of calls to Simulator::run + * and Simulator::insert_*. + */ + static void destroy (void); + + /** + * Register a new source of events from a remote simulation engine. + * This new source of events is used by the parallel scheduler + * to synchronize with the remote simulation engine by sending and + * receiving null messages. The synchronization algorithm used + * here is the classic Chandy/Misra/Bryant null-message algorithm. + * This method must be invoked bfore any call to Simulator::run. + * @param queue the queue to add to the list of event sources. + */ + static void add_parallel_queue (ParallelSimulatorQueue *queue); + + /** + * If there any any events lefts to be scheduled, return + * true. Return false otherwise. + */ + static bool is_finished (void); + /** + * If Simulator::is_finished returns true, the behavior of this + * method is undefined. Otherwise, it returns the microsecond-based + * time of the next event expected to be scheduled. + */ + static uint64_t next_us (void); + + /** + * Run the simulation until one of: + * - no events are present anymore + * - the user called Simulator::stop + * - the user called Simulator::stop_at_us and the + * expiration time of the next event to be processed + * is greater than or equal to the stop time. + */ + static void run (void); + /** + * If an event invokes this method, it will be the last + * event scheduled by the Simulator::run method before + * returning to the caller. + */ + static void stop (void); + /** + * Force the Simulator::run method to return to the caller + * when the expiration time of the next event to be processed + * is greater than or equal to the stop time. + * @param at the stop time. + */ + static void stop_at_us (uint64_t at); + + /** + * Schedule an event to expire at delta, relative to the + * current time. + * @param delta the expiration time relative to the current + * time. Expressed in microsecond units. + * @param event the event to schedule. + */ + static Event schedule_rel_us (uint64_t delta, Event event); + /** + * Schedule an event to expire at delta, relative to the + * current time. + * @param delta the expiration time, relative to the current + * time. Expressed in second units. + * @param event the event to schedule. + */ + static Event schedule_rel_s (double delta, Event event); + /** + * Schedule an event to expire at an absolute time. + * @param time the expiration time. Expressed in + * microsecond units. + * @param event the event to schedule. + */ + static Event schedule_abs_us (uint64_t time, Event event); + /** + * Schedule an event to expire at an absolute time. + * @param time the expiration time. Expressed in + * second units. + * @param event the event to schedule. + */ + static Event schedule_abs_s (double time, Event event); + /** + * Unschedule the event. i.e.: the removed event never expires. + * @param id the event to remove from the list of scheduled events. + */ + static Event remove (Event const id); + /** + * Return the "current time" in microsecond units. + */ + static uint64_t now_us (void); + /** + * Return the "current time" in second units. + */ + static double now_s (void); + /** + * Schedule an event to expire right now. i.e., it will + * expire after the currently-executing event is executed. + * If multiple events are scheduled with this method, + * they are executed in FIFO order: the events scheduled first + * are executed first. + * @param event the event to schedule now. + */ + static void schedule_now (Event event); + /** + * Schedule an event to expire when the Simulator::destroy method + * is invoked. Events are executed in FIFO order: the events + * scheduled first are executed first. + * @param event the event to schedule. + */ + static void schedule_destroy (Event event); +private: + Simulator (); + ~Simulator (); + static SimulatorPrivate *get_priv (void); + static SimulatorPrivate *m_priv; + static enum ListType { + LINKED_LIST, + BINARY_HEAP, + STD_MAP + } m_list_type; +}; + +}; // namespace yans + +#endif /* SIMULATOR_H */