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/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