made sure everything's thread safe
Pretty much everything already was, but I tweaked a few things to make
sure they stay that way and added various comments about that fact. Also
cleaned up a few things along the way and removed SafeMessageBuilder
because it wasn't.
diff --git a/aos/README.txt b/aos/README.txt
index da70440..7bf0144 100644
--- a/aos/README.txt
+++ b/aos/README.txt
@@ -29,6 +29,7 @@
type of implementation, objects referred to by interrupt service routines activated by the signal function
would require explicit specification of volatile storage, as well as other implementation-defined
restrictions.
-Everything that has to do different things when compiled for the crio or linux uses #ifdef __VXWORKS__ etc.
-The crio "queue" implementation uses 1 global instance and no synchronization, so it should only be used in code that gets called by the crio-side control loop infrastructure.
+
The C++ namespace aos is used for all of the aos code. The crio and linux_code namespaces are for APIs that only make sense on one platform or the other.
+
+Almost everything in aos/ is thread-safe. Files with a main() might not be, and some pieces of code explicitly say at their declaration that they aren't. Also, code which shares non-const pointers (including this) is not generally thread-safe. Other than those exceptions, everything is assumed to be thread-safe so the comments don't say so explicitly.
diff --git a/aos/build/aos.gyp b/aos/build/aos.gyp
index 3aaaf10..96cfc1b 100644
--- a/aos/build/aos.gyp
+++ b/aos/build/aos.gyp
@@ -7,9 +7,9 @@
{
'targets': [
# A target for things used by the logging implementation (except die) to
- # depend on that allows linking successfully with logging calls but has no
- # way to get initialized and so is basically useless unless something else
- # links in the rest of the logging stuff.
+ # depend on that allows linking successfully with logging calls. However,
+ # executables containing targets that depend on this still need a dependency
+ # on logging somewhere or else they won't link.
{
'target_name': 'logging_interface',
'type': 'static_library',
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
index 40a2570..903a872 100644
--- a/aos/build/queues/output/message_dec.rb
+++ b/aos/build/queues/output/message_dec.rb
@@ -199,47 +199,27 @@
create_Print(type_class,cpp_tree)
create_GetType(type_class, cpp_tree)
create_DoGetType(type_class, cpp_tree)
- create_DefaultConstructor(type_class, cpp_tree)
- create_InOrderConstructor(type_class, cpp_tree)
+ create_DefaultConstructor(type_class, cpp_tree)
+ create_InOrderConstructor(type_class, cpp_tree)
b_namespace = cpp_tree.get(b_loc = self.class.builder_loc(@loc))
- safetemplate = Types::TemplateClass.new(b_namespace,"SafeMessageBuilder")
- ifdef_statement = Types::PreprocessorIf.new(b_namespace,"!defined(__VXWORKS__) && !defined(__TEST_VXWORKS__)")
- ifdef_statement.add_member(safetemplate)
- b_namespace.add(ifdef_statement)
template = b_namespace.add_template("MessageBuilder")
- safetemplate.spec_args << t = @loc.to_cpp_id(@name)
template.spec_args << t = @loc.to_cpp_id(@name)
- safemsg_ptr_t = "SafeScopedMessagePtr< #{t}>"
msg_ptr_t = "ScopedMessagePtr< #{t}>"
- safemsg_bld_t = "SafeMessageBuilder< #{t}>"
msg_bld_t = "MessageBuilder< #{t}>"
- safetemplate.add_member(:private,"#{safemsg_ptr_t} msg_ptr_")
template.add_member(:private,"#{msg_ptr_t} msg_ptr_")
template.add_member(:private,"#{msg_bld_t}(const #{msg_bld_t}&)")
template.add_member(:private,"void operator=(const #{msg_bld_t}&)")
- safetemplate.add_member(:private,"friend class ::aos::Queue< #{t}>")
template.add_member(:private,"friend class ::aos::Queue< #{t}>")
cons = CPP::Constructor.new(template)
- unsafe_cons = CPP::Constructor.new(template)
- cons_ifdef_statement = CPP::PreprocessorIf.new(cons, unsafe_cons)
- cons_ifdef_statement.name = "!defined(__VXWORKS__) && !defined(__TEST_VXWORKS__)"
- template.add_member(:private,cons_ifdef_statement)
+ template.add_member(:private,cons)
cons.args << "RawQueue *queue"
cons.args << "#{t} *msg"
- unsafe_cons.args << "#{t} *msg"
cons.add_cons("msg_ptr_","queue","msg")
- unsafe_cons.add_cons("msg_ptr_","msg")
- cons = safetemplate.add_member(:private,CPP::Constructor.new(safetemplate))
- cons.args << "RawQueue *queue"
- cons.add_cons("msg_ptr_","queue")
- safetemplate.public
template.public
- DefineMembers(cpp_tree, safetemplate, safemsg_bld_t)
DefineMembers(cpp_tree, template, msg_bld_t)
-
end
def DefineMembers(cpp_tree, template, msg_bld_t)
send = template.def_func("bool","Send")
diff --git a/aos/build/queues/output/queue_dec.rb b/aos/build/queues/output/queue_dec.rb
index db4e1af..031c033 100644
--- a/aos/build/queues/output/queue_dec.rb
+++ b/aos/build/queues/output/queue_dec.rb
@@ -10,9 +10,6 @@
type = cpp_tree.get(@type)
return @type.loc.to_cpp_id(type.name)
end
- def full_ptr_name(cpp_tree)
- return "::aos::SafeScopedMessagePtr< #{full_message_name(cpp_tree)}>"
- end
def full_builder_name(cpp_tree)
return "::aos::MessageBuilder< #{full_message_name(cpp_tree)}>"
end
diff --git a/aos/common/controls/polytope.h b/aos/common/controls/polytope.h
index 6afe04b..e37346e 100644
--- a/aos/common/controls/polytope.h
+++ b/aos/common/controls/polytope.h
@@ -19,6 +19,10 @@
k_(k) {
}
+ // This is an initialization function shared across all instantiations of this
+ // template.
+ // This must be called at least once before calling any of the methods. It is
+ // not thread-safe.
static void Init() {
dd_set_global_constants();
}
diff --git a/aos/common/die.cc b/aos/common/die.cc
index e1b3b07..69b2aef 100644
--- a/aos/common/die.cc
+++ b/aos/common/die.cc
@@ -10,6 +10,7 @@
#include <stdint.h>
#include <string>
+#include <atomic>
namespace aos {
@@ -45,7 +46,7 @@
#endif
}
-bool test_mode = false;
+::std::atomic_bool test_mode(false);
} // namespace
@@ -57,7 +58,7 @@
fputs("aos fatal: ERROR!! details following\n", stderr);
va_copy(args1, args_in);
vfprintf(stderr, format, args1);
- if (!test_mode) {
+ if (!test_mode.load()) {
fputs("aos fatal: ERROR!! see stderr for details\n", stdout);
const std::string filename = GetFilename();
@@ -78,7 +79,7 @@
}
void SetDieTestMode(bool new_test_mode) {
- test_mode = new_test_mode;
+ test_mode.store(new_test_mode);
}
} // namespace aos
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index f520b35..969c0ee 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -38,7 +38,7 @@
Context *context = Context::Get();
context->implementation = implementation;
- global_top_implementation = implementation;
+ global_top_implementation.store(implementation);
}
void NewContext() {
diff --git a/aos/common/logging/logging_impl.h b/aos/common/logging/logging_impl.h
index a55e768..f24ce6a 100644
--- a/aos/common/logging/logging_impl.h
+++ b/aos/common/logging/logging_impl.h
@@ -11,6 +11,7 @@
#include <string>
#include <functional>
+#include <atomic>
#include "aos/common/logging/logging.h"
#include "aos/common/type_traits.h"
@@ -30,7 +31,8 @@
//
// It is implemented in logging_impl.cc and logging_interface.cc. They are
// separate so that code used by logging_impl.cc can link in
-// logging_interface.cc to use logging.
+// logging_interface.cc to use logging without creating a circular dependency.
+// However, any executables with such code still need logging_impl.cc linked in.
namespace aos {
namespace logging {
@@ -250,10 +252,13 @@
// goes.
namespace internal {
-extern LogImplementation *global_top_implementation;
+extern ::std::atomic<LogImplementation *> global_top_implementation;
// An separate instance of this class is accessible from each task/thread.
// NOTE: It will get deleted in the child of a fork.
+//
+// Get() and Delete() are implemented in the platform-specific interface.cc
+// file.
struct Context {
Context();
@@ -267,6 +272,8 @@
// Deletes the Context object for this task/thread so that the next Get() is
// called it will create a new one.
// It is valid to call this when Get() has never been called.
+ // This also gets called after a fork(2) in the new process, where it should
+ // still work to clean up any state.
static void Delete();
// Which one to log to right now.
diff --git a/aos/common/logging/logging_interface.cc b/aos/common/logging/logging_interface.cc
index 8c45afd..e4c6fcd 100644
--- a/aos/common/logging/logging_interface.cc
+++ b/aos/common/logging/logging_interface.cc
@@ -15,10 +15,10 @@
namespace logging {
namespace internal {
-LogImplementation *global_top_implementation(NULL);
+::std::atomic<LogImplementation *> global_top_implementation(NULL);
Context::Context()
- : implementation(global_top_implementation),
+ : implementation(global_top_implementation.load()),
sequence(0) {
cork_data.Reset();
}
diff --git a/aos/common/macros.h b/aos/common/macros.h
index 21482f6..e8558b2 100644
--- a/aos/common/macros.h
+++ b/aos/common/macros.h
@@ -8,6 +8,7 @@
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
+
// A macro to wrap arguments to macros that contain commas.
// Useful for DISALLOW_COPY_AND_ASSIGNing templated types with multiple template
// arguments.
diff --git a/aos/common/mutex.h b/aos/common/mutex.h
index a22df4e..ff953e4 100644
--- a/aos/common/mutex.h
+++ b/aos/common/mutex.h
@@ -30,7 +30,7 @@
// Locks the mutex. If it fails, it calls LOG(FATAL).
void Lock();
// Unlocks the mutex. Fails like Lock.
- // Multiple unlocking might be considered failure.
+ // Multiple unlocking is undefined.
void Unlock();
// Locks the mutex unless it is already locked.
// Returns whether it succeeded or not.
@@ -55,7 +55,6 @@
// A class that locks a Mutex when constructed and unlocks it when destructed.
// Designed to be used as a local variable so that
// the mutex will be unlocked when the scope is exited.
-// Should it fail for some reason, it dies with LOG(FATAL).
class MutexLocker {
public:
explicit MutexLocker(Mutex *mutex) : mutex_(mutex) {
diff --git a/aos/common/queue.h b/aos/common/queue.h
index 33dc377..da2a180 100644
--- a/aos/common/queue.h
+++ b/aos/common/queue.h
@@ -3,17 +3,9 @@
#include <assert.h>
-#if defined(__VXWORKS__) || defined(__TEST_VXWORKS__)
-#define USE_UNSAFE
-#else
-#undef USE_UNSAFE
-#endif
-
#include "aos/common/time.h"
#include "aos/common/macros.h"
-#ifndef USE_UNSAFE
#include "aos/linux_code/ipc_lib/queue.h"
-#endif // USE_UNSAFE
#include "aos/common/time.h"
namespace aos {
@@ -53,15 +45,11 @@
template <class T> class Queue;
template <class T> class MessageBuilder;
template <class T> class ScopedMessagePtr;
-#ifndef USE_UNSAFE
-template <class T> class SafeMessageBuilder;
-template <class T> class SafeScopedMessagePtr;
-#endif // USE_UNSAFE
// A ScopedMessagePtr<> manages a queue message pointer.
// It frees it properly when the ScopedMessagePtr<> goes out of scope or gets
// sent. By design, there is no way to get the ScopedMessagePtr to release the
-// message pointer.
+// message pointer to external code.
template <class T>
class ScopedMessagePtr {
public:
@@ -116,7 +104,6 @@
reset();
}
-#ifndef SWIG
// Implements a move constructor. This only takes rvalue references
// because we want to allow someone to say
// ScopedMessagePtr<X> ptr = queue.MakeMessage();
@@ -126,14 +113,9 @@
// clear out the source so there aren't 2 pointers to the message lying
// around.
ScopedMessagePtr(ScopedMessagePtr<T> &&ptr)
- :
-#ifndef USE_UNSAFE
- queue_(ptr.queue_),
-#endif // USE_UNSAFE
- msg_(ptr.msg_) {
+ : queue_(ptr.queue_), msg_(ptr.msg_) {
ptr.msg_ = NULL;
}
-#endif // SWIG
private:
// Provide access to set_queue and the constructor for init.
@@ -141,27 +123,20 @@
// Provide access to the copy constructor for MakeWithBuilder.
friend class aos::MessageBuilder<T>;
-#ifndef USE_UNSAFE
- // Only Queue should be able to build a queue.
+ // Only Queue should be able to build a message.
ScopedMessagePtr(RawQueue *queue, T *msg)
: queue_(queue), msg_(msg) {}
-#else
- ScopedMessagePtr(T *msg)
- : msg_(msg) {}
-#endif // USE_UNSAFE
// Sets the pointer to msg, freeing the old value if it was there.
// This is private because nobody should be able to get a pointer to a message
// that needs to be scoped without using the queue.
void reset(T *msg = NULL);
-#ifndef USE_UNSAFE
// Sets the queue that owns this message.
void set_queue(RawQueue *queue) { queue_ = queue; }
// The queue that the message is a part of.
RawQueue *queue_;
-#endif // USE_UNSAFE
// The message or NULL.
T *msg_;
@@ -171,8 +146,6 @@
// Specializations for the Builders will be automatically generated in the .q.h
// header files with all of the handy builder methods.
-// This builder uses an actual shm message pointer, which is more efficient and
-// more dangerous than the linux only SafeMessageBuilder.
template <class T>
class MessageBuilder {
public:
@@ -182,21 +155,14 @@
// TODO(aschuh): Base class
// T must be a Message with the same format as the messages generated by
-// the q files.
+// the .q files.
template <class T>
class Queue {
public:
typedef T Message;
Queue(const char *queue_name)
- : queue_name_(queue_name),
-#ifdef USE_UNSAFE
- queue_msg_(&msg_)
-#else
- queue_(NULL),
- queue_msg_(NULL, NULL)
-#endif // USE_UNSAFE
- {
+ : queue_name_(queue_name), queue_(NULL), queue_msg_(NULL, NULL) {
static_assert(shm_ok<T>::value,
"The provided message type can't be put in shmem.");
}
@@ -215,6 +181,9 @@
// Returns true if there was a new message available and we successfully
// fetched it.
bool FetchNext();
+
+ // Fetches the next message from the queue, waiting if necessary until there
+ // is one.
void FetchNextBlocking();
// Fetches the last message from the queue.
@@ -227,16 +196,17 @@
void FetchAnother();
// Returns the age of the message.
- const time::Time Age() { return time::Time::Now() - queue_msg_->sent_time; }
+ const time::Time Age() const { return time::Time::Now() - queue_msg_->sent_time; }
// Returns true if the latest value in the queue is newer than age mseconds.
- bool IsNewerThanMS(int age) {
+ // DEPRECATED(brians): Use IsNewerThan(const time::Time&) instead.
+ bool IsNewerThanMS(int age) const {
// TODO(aschuh): Log very verbosely if something is _ever_ stale.
- if (get() != NULL) {
- return Age() < time::Time::InMS(age);
- } else {
- return false;
- }
+ return IsNewerThan(time::Time::InMS(age));
+ }
+
+ bool IsNewerThan(const time::Time &age) const {
+ return get() != nullptr && Age() < age;
}
// Returns a pointer to the current message.
@@ -259,40 +229,26 @@
return msg;
}
-#ifndef USE_UNSAFE
- // Returns a scoped_ptr containing a message.
- // GCC will optimize away the copy constructor, so this is safe.
- SafeScopedMessagePtr<T> SafeMakeMessage();
-
- // Returns a message builder that contains a pre-allocated message.
- aos::SafeMessageBuilder<T> SafeMakeWithBuilder();
-#endif // USE_UNSAFE
-
-#ifndef SWIG
// Returns a scoped_ptr containing a message.
// GCC will optimize away the copy constructor, so this is safe.
ScopedMessagePtr<T> MakeMessage();
// Returns a message builder that contains a pre-allocated message.
aos::MessageBuilder<T> MakeWithBuilder();
-#endif // SWIG
const char *name() const { return queue_name_; }
private:
const char *queue_name_;
-#ifdef USE_UNSAFE
- // The unsafe queue only has 1 entry and no safety, so 1 message is fine.
- T msg_;
-#else
T *MakeRawMessage();
+
// Pointer to the queue that this object fetches from.
RawQueue *queue_;
int index_ = 0;
-#endif
// Scoped pointer holding the latest message or NULL.
ScopedMessagePtr<const T> queue_msg_;
+
DISALLOW_COPY_AND_ASSIGN(Queue<T>);
};
@@ -315,11 +271,6 @@
} // namespace aos
-#ifdef USE_UNSAFE
-#include "aos/crio/queue-tmpl.h"
-#else
#include "aos/linux_code/queue-tmpl.h"
-#endif
-#undef USE_UNSAFE
#endif // AOS_COMMON_QUEUE_H_
diff --git a/aos/common/queue_test.cc b/aos/common/queue_test.cc
index dfd18a2..36522f9 100644
--- a/aos/common/queue_test.cc
+++ b/aos/common/queue_test.cc
@@ -68,30 +68,6 @@
EXPECT_EQ(0x971, my_test_queue->test_int);
}
-// Tests that we can send a message with the message pointer and get it back.
-TEST_F(QueueTest, SendMessageBlockingSafe) {
- SafeScopedMessagePtr<TestingMessage> msg = my_test_queue.SafeMakeMessage();
- msg->test_bool = true;
- msg->test_int = 0x971;
- ASSERT_TRUE(msg.SendBlocking());
-
- ASSERT_TRUE(my_test_queue.FetchLatest());
- EXPECT_TRUE(my_test_queue->test_bool);
- EXPECT_EQ(0x971, my_test_queue->test_int);
-}
-
-// Tests that we can send a message with the message pointer and get it back.
-TEST_F(QueueTest, SendMessageSafe) {
- SafeScopedMessagePtr<TestingMessage> msg = my_test_queue.SafeMakeMessage();
- msg->test_bool = true;
- msg->test_int = 0x971;
- msg.Send();
-
- ASSERT_TRUE(my_test_queue.FetchLatest());
- EXPECT_TRUE(my_test_queue->test_bool);
- EXPECT_EQ(0x971, my_test_queue->test_int);
-}
-
// Tests that we can send a message with the builder and get it back.
TEST_F(QueueTest, SendWithBuilder) {
my_test_queue.MakeWithBuilder().test_bool(true).test_int(0x971).Send();
diff --git a/aos/common/time.h b/aos/common/time.h
index 846366c..0440d91 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -205,8 +205,7 @@
}
// Enables returning the mock time value for Now instead of checking the
- // system clock. This should only be used when testing things depending on
- // time, or many things may/will break.
+ // system clock.
static void EnableMockTime(const Time &now = Now());
// Calls SetMockTime with the current actual time.
static void UpdateMockTime();
diff --git a/aos/linux_code/configuration.cc b/aos/linux_code/configuration.cc
index 55fff84..e4d5d80 100644
--- a/aos/linux_code/configuration.cc
+++ b/aos/linux_code/configuration.cc
@@ -44,6 +44,7 @@
unique_c_ptr<ifaddrs, freeifaddrs> addrs_deleter(addrs);
for (; addrs != nullptr; addrs = addrs->ifa_next) {
+ // ifa_addr tends to be nullptr on CAN interfaces.
if (addrs->ifa_addr != nullptr && addrs->ifa_addr->sa_family == AF_INET) {
if (strcmp(kLinuxNetInterface, addrs->ifa_name) == 0) {
static const in_addr r =
diff --git a/aos/linux_code/core.cc b/aos/linux_code/core.cc
index 5b580ef..189df1d 100644
--- a/aos/linux_code/core.cc
+++ b/aos/linux_code/core.cc
@@ -13,7 +13,7 @@
// Initializes shared memory. This is the only file that will create the shared
// memory file if it doesn't already exist (and set everything up).
//
-// Will also create the file given as a first argument.
+// Will also touch the file given as a first argument.
int main(int argc, char **argv) {
aos::InitCreate();
diff --git a/aos/linux_code/init.cc b/aos/linux_code/init.cc
index 05004a2..d8864fe 100644
--- a/aos/linux_code/init.cc
+++ b/aos/linux_code/init.cc
@@ -44,7 +44,7 @@
WriteCoreDumps();
}
-int LockAllMemory() {
+void LockAllMemory() {
InitStart();
if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
PDie("%s-init: mlockall failed", program_invocation_short_name);
@@ -55,8 +55,6 @@
uint8_t data[4096 * 8];
// Not 0 because linux might optimize that to a 0-filled page.
memset(data, 1, sizeof(data));
-
- return 0;
}
// Do the initialization code that is necessary for both realtime and
@@ -76,11 +74,14 @@
void Init(int relative_priority) {
if (getenv(kNoRealtimeEnvironmentVariable) == NULL) { // if nobody set it
LockAllMemory();
+
// Only let rt processes run for 3 seconds straight.
SetSoftRLimit(RLIMIT_RTTIME, 3000000, true);
+
// Allow rt processes up to priority 40.
SetSoftRLimit(RLIMIT_RTPRIO, 40, false);
- // Set our process to priority 40.
+
+ // Set our process to the appropriate priority.
struct sched_param param;
param.sched_priority = 30 + relative_priority;
if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
diff --git a/aos/linux_code/init.h b/aos/linux_code/init.h
index c2b2635..538684e 100644
--- a/aos/linux_code/init.h
+++ b/aos/linux_code/init.h
@@ -3,6 +3,10 @@
namespace aos {
+// In order to use shared memory, one of the Init* functions must be called in
+// exactly 1 thread per process. It is OK to keep going without calling one of
+// them again after fork(2)ing.
+
// Does the non-realtime parts of the initialization process.
void InitNRT();
// Initializes everything, including the realtime stuff.
@@ -17,7 +21,8 @@
void Cleanup();
// Sets up this process to write core dump files.
-// This is called by Init*.
+// This is called by Init*, but it's here for other files that want this
+// behavior without calling Init*.
void WriteCoreDumps();
} // namespace aos
diff --git a/aos/linux_code/ipc_lib/shared_mem.c b/aos/linux_code/ipc_lib/shared_mem.c
index a132233..e0be160 100644
--- a/aos/linux_code/ipc_lib/shared_mem.c
+++ b/aos/linux_code/ipc_lib/shared_mem.c
@@ -8,6 +8,7 @@
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
+#include <assert.h>
#include "aos/linux_code/ipc_lib/core_lib.h"
#include "aos/common/logging/logging.h"
@@ -39,6 +40,7 @@
// TODO(brians): madvise(2) it to put this shm in core dumps.
void aos_core_create_shared_mem(enum aos_core_create to_create) {
+ assert(global_core == NULL);
static struct aos_core global_core_data;
global_core = &global_core_data;
diff --git a/aos/linux_code/ipc_lib/shared_mem.h b/aos/linux_code/ipc_lib/shared_mem.h
index 6968df7..33cb607 100644
--- a/aos/linux_code/ipc_lib/shared_mem.h
+++ b/aos/linux_code/ipc_lib/shared_mem.h
@@ -47,6 +47,7 @@
reference
};
struct aos_core {
+ // Non-0 if we "own" shared_mem and should shm_unlink(3) it when we're done.
int owner;
void *shared_mem;
// How large the chunk of shared memory is.
diff --git a/aos/linux_code/logging/linux_interface.cc b/aos/linux_code/logging/linux_interface.cc
index 9889c07..cbc114e 100644
--- a/aos/linux_code/logging/linux_interface.cc
+++ b/aos/linux_code/logging/linux_interface.cc
@@ -42,7 +42,7 @@
} // namespace
Context *Context::Get() {
- if (my_context == NULL) {
+ if (__builtin_expect(my_context == NULL, 0)) {
my_context = new Context();
my_context->name = GetMyName();
if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
diff --git a/aos/linux_code/queue-tmpl.h b/aos/linux_code/queue-tmpl.h
index 64121f3..522bf6b 100644
--- a/aos/linux_code/queue-tmpl.h
+++ b/aos/linux_code/queue-tmpl.h
@@ -28,138 +28,6 @@
msg_ = msg;
}
-// A SafeScopedMessagePtr<> manages a message pointer.
-// It frees it properly when the ScopedMessagePtr<> goes out of scope or gets
-// sent. By design, there is no way to get the ScopedMessagePtr to release the
-// message pointer. When the message gets sent, it allocates a queue message,
-// copies the data into it, and then sends it. Copies copy the message.
-template <class T>
-class SafeScopedMessagePtr {
- public:
- // Returns a pointer to the message.
- // This stays valid until Send or the destructor have been called.
- T *get() { return msg_; }
-
- T &operator*() {
- T *msg = get();
- assert(msg != NULL);
- return *msg;
- }
-
- T *operator->() {
- T *msg = get();
- assert(msg != NULL);
- return msg;
- }
-
- operator bool() {
- return msg_ != NULL;
- }
-
- const T *get() const { return msg_; }
-
- const T &operator*() const {
- const T *msg = get();
- assert(msg != NULL);
- return *msg;
- }
-
- const T *operator->() const {
- const T *msg = get();
- assert(msg != NULL);
- return msg;
- }
-
- // Sends the message and removes our reference to it.
- // If the queue is full, over-rides the oldest message in it with our new
- // message.
- // Returns true on success, and false otherwise.
- // The message will be freed.
- bool Send() {
- assert(msg_ != NULL);
- assert(queue_ != NULL);
- msg_->SetTimeToNow();
- T *shm_msg = static_cast<T *>(queue_->GetMessage());
- if (shm_msg == NULL) {
- return false;
- }
- *shm_msg = *msg_;
- bool return_value = queue_->WriteMessage(shm_msg, RawQueue::kOverride);
- reset();
- return return_value;
- }
-
- // Sends the message and removes our reference to it.
- // If the queue is full, blocks until it is no longer full.
- // Returns true on success, and false otherwise.
- // Frees the message.
- bool SendBlocking() {
- assert(msg_ != NULL);
- assert(queue_ != NULL);
- msg_->SetTimeToNow();
- T *shm_msg = static_cast<T *>(queue_->GetMessage());
- if (shm_msg == NULL) {
- return false;
- }
- *shm_msg = *msg_;
- bool return_value = queue_->WriteMessage(shm_msg, RawQueue::kBlock);
- reset();
- return return_value;
- }
-
- // Frees the contained message.
- ~SafeScopedMessagePtr() {
- reset();
- }
-
- // Implements a move constructor to take the message pointer from the
- // temporary object to save work.
- SafeScopedMessagePtr(SafeScopedMessagePtr<T> &&ptr)
- : queue_(ptr.queue_),
- msg_(ptr.msg_) {
- ptr.msg_ = NULL;
- }
-
- // Copy constructor actually copies the data.
- SafeScopedMessagePtr(const SafeScopedMessagePtr<T> &ptr)
- : queue_(ptr.queue_),
- msg_(NULL) {
- reset(new T(*ptr.get()));
- }
- // Equal operator copies the data.
- void operator=(const SafeScopedMessagePtr<T> &ptr) {
- queue_ = ptr.queue_;
- reset(new T(*ptr.get()));
- }
-
- private:
- // Provide access to private constructor.
- friend class aos::Queue<typename std::remove_const<T>::type>;
- friend class aos::SafeMessageBuilder<T>;
-
- // Only Queue should be able to build a message pointer.
- SafeScopedMessagePtr(RawQueue *queue)
- : queue_(queue), msg_(new T()) {}
-
- // Sets the pointer to msg, freeing the old value if it was there.
- // This is private because nobody should be able to get a pointer to a message
- // that needs to be scoped without using the queue.
- void reset(T *msg = NULL) {
- if (msg_) {
- delete msg_;
- }
- msg_ = msg;
- }
-
- // Sets the queue that owns this message.
- void set_queue(RawQueue *queue) { queue_ = queue; }
-
- // The queue that the message is a part of.
- RawQueue *queue_;
- // The message or NULL.
- T *msg_;
-};
-
template <class T>
void Queue<T>::Init() {
if (queue_ == NULL) {
@@ -223,14 +91,6 @@
}
template <class T>
-SafeScopedMessagePtr<T> Queue<T>::SafeMakeMessage() {
- Init();
- SafeScopedMessagePtr<T> safe_msg(queue_);
- safe_msg->Zero();
- return safe_msg;
-}
-
-template <class T>
ScopedMessagePtr<T> Queue<T>::MakeMessage() {
Init();
return ScopedMessagePtr<T>(queue_, MakeRawMessage());
@@ -249,21 +109,4 @@
return aos::MessageBuilder<T>(queue_, MakeRawMessage());
}
-
-// This builder uses the safe message pointer so that it can be safely copied
-// in places where it could be leaked.
-template <class T>
-class SafeMessageBuilder {
- public:
- typedef T Message;
- bool Send();
-};
-
-template <class T>
-aos::SafeMessageBuilder<T> Queue<T>::SafeMakeWithBuilder() {
- Init();
- return aos::SafeMessageBuilder<T>(queue_);
-}
-
-
} // namespace aos
diff --git a/aos/prime/input/joystick_input.cc b/aos/prime/input/joystick_input.cc
index 6a6606e..7e2f0cd 100644
--- a/aos/prime/input/joystick_input.cc
+++ b/aos/prime/input/joystick_input.cc
@@ -70,7 +70,8 @@
}
}
}
-
+ }
+ {
using driver_station::ControlBit;
if (data.PosEdge(ControlBit::kFmsAttached)) {
LOG(INFO, "PosEdge(kFmsAttached)\n");
diff --git a/aos/prime/output/motor_output.cc b/aos/prime/output/motor_output.cc
index c02a11b..b6d59e2 100644
--- a/aos/prime/output/motor_output.cc
+++ b/aos/prime/output/motor_output.cc
@@ -51,6 +51,10 @@
time::PhasedLoopXMS(5, 1000);
::aos::time::Time::UpdateMockTime();
+ no_robot_state_.Print();
+ fake_robot_state_.Print();
+ sending_failed_.Print();
+
values_.digital_module = -1;
// 0 means output disabled.
memset(&values_.pwm_outputs, 0x00, sizeof(values_.pwm_outputs));
@@ -63,8 +67,12 @@
RunIteration();
::aos::robot_state.FetchLatest();
- if (!::aos::robot_state.get() || ::aos::robot_state->fake) {
- LOG(DEBUG, "fake robot state -> not outputting\n");
+ if (!::aos::robot_state.get()) {
+ LOG_INTERVAL(no_robot_state_);
+ continue;
+ }
+ if (::aos::robot_state->fake) {
+ LOG_INTERVAL(fake_robot_state_);
continue;
}
@@ -75,7 +83,7 @@
continue;
}
if (socket_.Send(buffer, size) != size) {
- LOG(WARNING, "sending outputs failed\n");
+ LOG_INTERVAL(sending_failed_);
continue;
} else {
LOG(DEBUG, "sent outputs\n");
diff --git a/aos/prime/output/motor_output.h b/aos/prime/output/motor_output.h
index 8c613e9..7d856bc 100644
--- a/aos/prime/output/motor_output.h
+++ b/aos/prime/output/motor_output.h
@@ -10,12 +10,13 @@
#include "aos/common/network/send_socket.h"
#include "aos/common/byteorder.h"
#include "aos/common/type_traits.h"
+#include "aos/common/util/log_interval.h"
namespace aos {
// A class for sending output values to a cRIO.
// values_ gets completely reset each time through, so RunIteration() needs to
-// set everything each time.
+// set everything each time (except solenoids).
class MotorOutput {
public:
MotorOutput();
@@ -51,7 +52,7 @@
void SetSolenoid(uint8_t channel, bool set);
void SetPWMOutput(uint8_t channel, double value,
const MotorControllerBounds &bounds);
- void SetRawPWMOutput(uint8_t cahnnel, uint8_t value);
+ void SetRawPWMOutput(uint8_t channel, uint8_t value);
void DisablePWMOutput(uint8_t channel);
void SetDigitalOutput(uint8_t channel, bool value);
@@ -65,6 +66,16 @@
virtual void RunIteration() = 0;
network::SendSocket socket_;
+
+ util::SimpleLogInterval no_robot_state_ =
+ util::SimpleLogInterval(::aos::time::Time::InSeconds(0.5), INFO,
+ "no robot state -> not outputting");
+ util::SimpleLogInterval fake_robot_state_ =
+ util::SimpleLogInterval(::aos::time::Time::InSeconds(0.5), DEBUG,
+ "fake robot state -> not outputting");
+ util::SimpleLogInterval sending_failed_ =
+ util::SimpleLogInterval(::aos::time::Time::InSeconds(0.1), WARNING,
+ "sending outputs failed");
};
} // namespace aos
diff --git a/aos/prime/output/output.gyp b/aos/prime/output/output.gyp
index 20fe699..1fadff0 100644
--- a/aos/prime/output/output.gyp
+++ b/aos/prime/output/output.gyp
@@ -12,10 +12,12 @@
'<(EXTERNALS):WPILib-NetworkRobotValues',
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/messages/messages.gyp:robot_state',
+ '<(AOS)/common/util/util.gyp:log_interval',
],
'export_dependent_settings': [
'<(AOS)/common/network/network.gyp:socket',
'<(EXTERNALS):WPILib-NetworkRobotValues',
+ '<(AOS)/common/util/util.gyp:log_interval',
],
},
{