diff options
author | David Crocker <dcrocker@eschertech.com> | 2018-04-06 00:38:19 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2018-04-06 00:38:19 +0300 |
commit | d4b10780d217244008dee464a45823cf3416f53b (patch) | |
tree | 857f3dbabd03c35ee297e33b38dc0debf581f692 | |
parent | a2ecb67c8a8c08f1d5fcb455378e000066957ff2 (diff) |
More RTOS work again
Increased Heat task stack to avoid crash when tuning a heater
Protected vsnprintf etc. from reentrancy
Use scheduler suspension instead of disabling interrupts for most
critical sections
-rw-r--r-- | EdgeRelease/Duet2CombinedFirmware.bin | bin | 371924 -> 372172 bytes | |||
-rw-r--r-- | src/BugList.txt | 5 | ||||
-rw-r--r-- | src/GCodes/GCodeBuffer.cpp | 2 | ||||
-rw-r--r-- | src/Heating/Heat.cpp | 2 | ||||
-rw-r--r-- | src/Libraries/General/IP4String.cpp | 6 | ||||
-rw-r--r-- | src/Libraries/General/StringRef.cpp | 46 | ||||
-rw-r--r-- | src/Libraries/General/StringRef.h | 5 | ||||
-rw-r--r-- | src/Libraries/General/strtod.cpp | 5 | ||||
-rw-r--r-- | src/Memory usage.ods | bin | 17473 -> 18704 bytes | |||
-rw-r--r-- | src/Movement/BedProbing/Grid.cpp | 4 | ||||
-rw-r--r-- | src/Movement/DDA.h | 2 | ||||
-rw-r--r-- | src/Networking/HttpResponder.cpp | 4 | ||||
-rw-r--r-- | src/Networking/HttpResponder.h | 4 | ||||
-rw-r--r-- | src/Networking/NetworkResponder.h | 2 | ||||
-rw-r--r-- | src/OutputMemory.cpp | 44 | ||||
-rw-r--r-- | src/OutputMemory.h | 33 | ||||
-rw-r--r-- | src/Platform.h | 6 | ||||
-rw-r--r-- | src/RTOS work pending.txt | 6 | ||||
-rw-r--r-- | src/RTOSIface.h | 48 | ||||
-rw-r--r-- | src/Tasks.cpp | 7 | ||||
-rw-r--r-- | src/Tools/Tool.cpp | 4 | ||||
-rw-r--r-- | src/Version.h | 2 |
22 files changed, 153 insertions, 84 deletions
diff --git a/EdgeRelease/Duet2CombinedFirmware.bin b/EdgeRelease/Duet2CombinedFirmware.bin Binary files differindex 4eb54bf8..e2153bb6 100644 --- a/EdgeRelease/Duet2CombinedFirmware.bin +++ b/EdgeRelease/Duet2CombinedFirmware.bin diff --git a/src/BugList.txt b/src/BugList.txt index ee25f57a..9b77d7cc 100644 --- a/src/BugList.txt +++ b/src/BugList.txt @@ -111,6 +111,7 @@ Remaining: - [done in 2.0, test] Allow Z jerk down to 0.2mm/sec - [done in 2.0, ok] BUG: no call to HttpResponder::CheckSessions - BUG: G29 height map is way below bed. Happened on Ormerod. When probing the bed with simple G30 and compensation is applied, correct for the height map offset +- Motor stall detection Z probe. Run deploy/retract macros before/after each probe, as for bltouch, or not? - Unexpected heaters off/tool selection behaviour, https://www.duet3d.com/forum/thread.php?pid=43059#p43059 - warn when using : where ; was probably meant - check out G30 H parameter, https://www.duet3d.com/forum/thread.php?pid=42322#p42322 @@ -131,6 +132,8 @@ Remaining: - apostrophe in quoted filename - looks like we get a Pop underflow message when you send DWC jog commands and axes are not homed - Add warning message when print exceeds bounds +- Does bltouch need a default recovery time? +- Should bltouch use digital probe mode? Some users having problems with P25 in G31 command. - How should we lift X on a CoreXZ printer before homing? - if a homing command in an SD print file is aborted due to e.g. G1 Z5 in the homing file, error message should be written to both DWC and PanelDue @@ -203,5 +206,3 @@ Later versions: - Add T parameter to M207 - look at supporting SIZE in FTP - Make mp.delta.hmz0sK, hmz0scK and dsk 64-bit in SAM4E versions, to increase movement limit - also increase K2? - -- SAME7 boot loader - could base on SAM-BA, see http://hobbygenius.co.uk/blog/1633 diff --git a/src/GCodes/GCodeBuffer.cpp b/src/GCodes/GCodeBuffer.cpp index cdef1518..8877a83a 100644 --- a/src/GCodes/GCodeBuffer.cpp +++ b/src/GCodes/GCodeBuffer.cpp @@ -262,7 +262,7 @@ bool GCodeBuffer::LineFinished() { if (hadLineNumber) { - snprintf(gcodeBuffer, ARRAY_SIZE(gcodeBuffer), "M998 P%u", lineNumber); // request resend + SafeSnprintf(gcodeBuffer, ARRAY_SIZE(gcodeBuffer), "M998 P%u", lineNumber); // request resend } else { diff --git a/src/Heating/Heat.cpp b/src/Heating/Heat.cpp index d1e345c0..9db52383 100644 --- a/src/Heating/Heat.cpp +++ b/src/Heating/Heat.cpp @@ -33,7 +33,7 @@ Licence: GPL # include "Tasks.h" -constexpr uint32_t HeaterTaskStackWords = 128; // task stack size in dwords +constexpr uint32_t HeaterTaskStackWords = 400; // task stack size in dwords, must be large enough for auto tuning static Task<HeaterTaskStackWords> heaterTask; extern "C" void HeaterTask(void * pvParameters) diff --git a/src/Libraries/General/IP4String.cpp b/src/Libraries/General/IP4String.cpp index 7f03e836..722e5fa2 100644 --- a/src/Libraries/General/IP4String.cpp +++ b/src/Libraries/General/IP4String.cpp @@ -6,16 +6,16 @@ */ #include "IP4String.h" -#include <cstdio> +#include "StringRef.h" IP4String::IP4String(const uint8_t ip[4]) { - snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + SafeSnprintf(buf, sizeof(buf)/sizeof(buf[0]), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); } IP4String::IP4String(uint32_t ip) { - snprintf(buf, sizeof(buf)/sizeof(buf[0]), "%u.%u.%u.%u", + SafeSnprintf(buf, sizeof(buf)/sizeof(buf[0]), "%u.%u.%u.%u", (unsigned int)(ip & 0xFFu), (unsigned int)((ip >> 8) & 0xFFu), (unsigned int)((ip >> 16) & 0xFFu), (unsigned int)((ip >> 24) & 0xFFu)); } diff --git a/src/Libraries/General/StringRef.cpp b/src/Libraries/General/StringRef.cpp index a469cec1..5f9c99fe 100644 --- a/src/Libraries/General/StringRef.cpp +++ b/src/Libraries/General/StringRef.cpp @@ -10,6 +10,10 @@ #include <cstdio> #include "WMath.h" +#ifdef RTOS +# include "RTOSIface.h" +#endif + // Need to define strnlen here because it isn't ISO standard size_t strnlen(const char *s, size_t n) { @@ -21,6 +25,36 @@ size_t strnlen(const char *s, size_t n) return rslt; } +// Thread safe version of vsnprintf. The standard one uses a buffer in the _reent structure. +extern "C" int SafeVsnprintf(char* buffer, size_t buf_size, const char* format, va_list vlist) +{ +#ifdef RTOS + TaskCriticalSectionLocker lock; +#endif + return vsnprintf(buffer, buf_size, format, vlist); +} + +extern "C" int SafeSnprintf(char* buffer, size_t buf_size, const char* format, ...) +{ + va_list vargs; + va_start(vargs, format); + const int ret = SafeVsnprintf(buffer, buf_size, format, vargs); + va_end(vargs); + return ret; +} + +extern "C" int SafeSscanf(const char* s, const char* format, ...) +{ + va_list vargs; + va_start(vargs, format); +#ifdef RTOS + TaskCriticalSectionLocker lock; +#endif + const int ret = vsscanf(s, format, vargs); + va_end(vargs); + return ret; +} + //************************************************************************************************* // StringRef class member implementations @@ -33,14 +67,14 @@ int StringRef::printf(const char *fmt, ...) const { va_list vargs; va_start(vargs, fmt); - const int ret = vsnprintf(p, len, fmt, vargs); + const int ret = SafeVsnprintf(p, len, fmt, vargs); va_end(vargs); return ret; } int StringRef::vprintf(const char *fmt, va_list vargs) const { - return vsnprintf(p, len, fmt, vargs); + return SafeVsnprintf(p, len, fmt, vargs); } int StringRef::catf(const char *fmt, ...) const @@ -50,7 +84,7 @@ int StringRef::catf(const char *fmt, ...) const { va_list vargs; va_start(vargs, fmt); - const int ret = vsnprintf(p + n, len - n, fmt, vargs); + const int ret = SafeVsnprintf(p + n, len - n, fmt, vargs); va_end(vargs); return ret + n; } @@ -62,7 +96,7 @@ int StringRef::vcatf(const char *fmt, va_list vargs) const const size_t n = strlen(); if (n + 1 < len) // if room for at least 1 more character and a null { - return vsnprintf(p + n, len - n, fmt, vargs) + n; + return SafeVsnprintf(p + n, len - n, fmt, vargs) + n; } return 0; } @@ -129,7 +163,3 @@ bool StringRef::Prepend(const char *src) const } // End - - - - diff --git a/src/Libraries/General/StringRef.h b/src/Libraries/General/StringRef.h index 6c74fd71..c8800aaa 100644 --- a/src/Libraries/General/StringRef.h +++ b/src/Libraries/General/StringRef.h @@ -15,6 +15,11 @@ // Need to declare strnlen here because it isn't ISO standard size_t strnlen(const char *s, size_t n); +// Thread safe versions of vsnprintf etc. +extern "C" int SafeVsnprintf(char* buffer, size_t buf_size, const char* format, va_list vlist); +extern "C" int SafeSnprintf(char* buffer, size_t buf_size, const char* format, ...) __attribute__ ((format (printf, 3, 4))); +extern "C" int SafeSscanf(const char* s, const char* format, ...) __attribute__ ((format (scanf, 2, 3))); + // Class to describe a string buffer, including its length. This saves passing buffer lengths around everywhere. class StringRef { diff --git a/src/Libraries/General/strtod.cpp b/src/Libraries/General/strtod.cpp index cc7ef924..8cc7b963 100644 --- a/src/Libraries/General/strtod.cpp +++ b/src/Libraries/General/strtod.cpp @@ -9,9 +9,8 @@ * 2. It allocates and releases heap memory, which is not nice. * * Limitations of this version - * 1. Rounding to nearest float may not always be correct. - * 2. Doesn't handle more than 9 digits (excluding any leading zeros) before the decimal point. Numbers greater than 2^64-1 or less then -2^64-1 - * will be incorrectly converted unless expressed in scientific notation. + * 1. Rounding to nearest double may not always be correct. + * 2. May not handle overflow for stupidly large numbers correctly. */ #include <cstdlib> // to pull in the standard declarations of strtod etc. diff --git a/src/Memory usage.ods b/src/Memory usage.ods Binary files differindex 84f8b90e..5a24f973 100644 --- a/src/Memory usage.ods +++ b/src/Memory usage.ods diff --git a/src/Movement/BedProbing/Grid.cpp b/src/Movement/BedProbing/Grid.cpp index c994699a..31e39218 100644 --- a/src/Movement/BedProbing/Grid.cpp +++ b/src/Movement/BedProbing/Grid.cpp @@ -105,11 +105,11 @@ bool GridDefinition::ReadParameters(const StringRef& s, int version) switch (version) { case 1: - ok = (sscanf(s.c_str(), "%f,%f,%f,%f,%f,%f,%f,%lu,%lu", &xMin, &xMax, &yMin, &yMax, &radius, &xSpacing, &ySpacing, &numX, &numY) == 9); + ok = (SafeSscanf(s.c_str(), "%f,%f,%f,%f,%f,%f,%f,%lu,%lu", &xMin, &xMax, &yMin, &yMax, &radius, &xSpacing, &ySpacing, &numX, &numY) == 9); break; case 0: - ok = (sscanf(s.c_str(), "%f,%f,%f,%f,%f,%f,%lu,%lu", &xMin, &xMax, &yMin, &yMax, &radius, &xSpacing, &numX, &numY) == 8); + ok = (SafeSscanf(s.c_str(), "%f,%f,%f,%f,%f,%f,%lu,%lu", &xMin, &xMax, &yMin, &yMax, &radius, &xSpacing, &numX, &numY) == 8); if (ok) { ySpacing = xSpacing; diff --git a/src/Movement/DDA.h b/src/Movement/DDA.h index 72124b30..e1c2e2f5 100644 --- a/src/Movement/DDA.h +++ b/src/Movement/DDA.h @@ -206,7 +206,7 @@ private: // These are calculated from the above and used in the ISR, so they are set up by Prepare() uint32_t clocksNeeded; // in clocks uint32_t moveStartTime; // clock count at which the move was started - uint32_t startSpeedTimesCdivA; // the number of clocks it would have taken t reach the start speed form rest + uint32_t startSpeedTimesCdivA; // the number of clocks it would have taken to reach the start speed from rest uint32_t topSpeedTimesCdivAPlusDecelStartClocks; int32_t extraAccelerationClocks; // the additional number of clocks needed because we started the move at less than topSpeed. Negative after ReduceHomingSpeed has been called. diff --git a/src/Networking/HttpResponder.cpp b/src/Networking/HttpResponder.cpp index 6b2d9e90..d29b8008 100644 --- a/src/Networking/HttpResponder.cpp +++ b/src/Networking/HttpResponder.cpp @@ -1287,8 +1287,8 @@ HttpResponder::HttpSession HttpResponder::sessions[MaxHttpSessions]; unsigned int HttpResponder::numSessions = 0; unsigned int HttpResponder::clientsServed = 0; -uint32_t HttpResponder::seq = 0; -OutputStack HttpResponder::gcodeReply; +volatile uint32_t HttpResponder::seq = 0; +volatile OutputStack HttpResponder::gcodeReply; Mutex HttpResponder::gcodeReplyMutex; // End diff --git a/src/Networking/HttpResponder.h b/src/Networking/HttpResponder.h index 939beca4..3b39a1cb 100644 --- a/src/Networking/HttpResponder.h +++ b/src/Networking/HttpResponder.h @@ -112,8 +112,8 @@ private: static unsigned int clientsServed; // Responses from GCodes class - static uint32_t seq; // Sequence number for G-Code replies - static OutputStack gcodeReply; + static volatile uint32_t seq; // Sequence number for G-Code replies + static volatile OutputStack gcodeReply; static Mutex gcodeReplyMutex; }; diff --git a/src/Networking/NetworkResponder.h b/src/Networking/NetworkResponder.h index 6c03980c..6bda80e3 100644 --- a/src/Networking/NetworkResponder.h +++ b/src/Networking/NetworkResponder.h @@ -76,7 +76,7 @@ protected: // Buffers for sending responses OutputBuffer *outBuf; - OutputStack outStack; + OutputStack outStack; // not volatile because only one task accesses it FileStore *fileBeingSent; NetworkBuffer *fileBuffer; diff --git a/src/OutputMemory.cpp b/src/OutputMemory.cpp index 5c2486ab..766ea98d 100644 --- a/src/OutputMemory.cpp +++ b/src/OutputMemory.cpp @@ -34,6 +34,8 @@ void OutputBuffer::IncreaseReferences(size_t refs) { if (refs > 0) { + TaskCriticalSectionLocker lock; + for(OutputBuffer *item = this; item != nullptr; item = item->Next()) { item->references += refs; @@ -92,7 +94,7 @@ size_t OutputBuffer::printf(const char *fmt, ...) char formatBuffer[FORMAT_STRING_LENGTH]; va_list vargs; va_start(vargs, fmt); - vsnprintf(formatBuffer, ARRAY_SIZE(formatBuffer), fmt, vargs); + SafeVsnprintf(formatBuffer, ARRAY_SIZE(formatBuffer), fmt, vargs); va_end(vargs); return copy(formatBuffer); @@ -101,7 +103,7 @@ size_t OutputBuffer::printf(const char *fmt, ...) size_t OutputBuffer::vprintf(const char *fmt, va_list vargs) { char formatBuffer[FORMAT_STRING_LENGTH]; - vsnprintf(formatBuffer, ARRAY_SIZE(formatBuffer), fmt, vargs); + SafeVsnprintf(formatBuffer, ARRAY_SIZE(formatBuffer), fmt, vargs); return cat(formatBuffer); } @@ -111,7 +113,7 @@ size_t OutputBuffer::catf(const char *fmt, ...) char formatBuffer[FORMAT_STRING_LENGTH]; va_list vargs; va_start(vargs, fmt); - vsnprintf(formatBuffer, ARRAY_SIZE(formatBuffer), fmt, vargs); + SafeVsnprintf(formatBuffer, ARRAY_SIZE(formatBuffer), fmt, vargs); va_end(vargs); formatBuffer[ARRAY_UPB(formatBuffer)] = 0; @@ -342,11 +344,11 @@ bool OutputBuffer::WriteToFile(FileData& f) const } } -// Allocates an output buffer instance which can be used for (large) string outputs. This must be thread safe. +// Allocates an output buffer instance which can be used for (large) string outputs. This must be thread safe. Not safe to call from interrupts! /*static*/ bool OutputBuffer::Allocate(OutputBuffer *&buf) { { - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; buf = freeOutputBuffers; if (buf != nullptr) @@ -439,7 +441,7 @@ bool OutputBuffer::WriteToFile(FileData& f) const // Releases an output buffer instance and returns the next entry from the chain /*static */ OutputBuffer *OutputBuffer::Release(OutputBuffer *buf) { - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; OutputBuffer * const nextBuffer = buf->next; // If this one is reused by another piece of code, don't free it up @@ -476,7 +478,7 @@ bool OutputBuffer::WriteToFile(FileData& f) const // OutputStack class implementation // Push an OutputBuffer chain to the stack -void OutputStack::Push(OutputBuffer *buffer) +void OutputStack::Push(OutputBuffer *buffer) volatile { if (count == OUTPUT_STACK_DEPTH) { @@ -488,20 +490,20 @@ void OutputStack::Push(OutputBuffer *buffer) if (buffer != nullptr) { buffer->whenQueued = millis(); - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; items[count++] = buffer; } } -// Pop an OutputBuffer chain or return NULL if none is available -OutputBuffer *OutputStack::Pop() +// Pop an OutputBuffer chain or return nullptr if none is available +OutputBuffer *OutputStack::Pop() volatile { if (count == 0) { return nullptr; } - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; OutputBuffer *item = items[0]; for(size_t i = 1; i < count; i++) { @@ -513,7 +515,7 @@ OutputBuffer *OutputStack::Pop() } // Returns the first item from the stack or NULL if none is available -OutputBuffer *OutputStack::GetFirstItem() const +OutputBuffer *OutputStack::GetFirstItem() const volatile { if (count == 0) { @@ -523,9 +525,9 @@ OutputBuffer *OutputStack::GetFirstItem() const } // Set the first item of the stack. If it's NULL, then the first item will be removed -void OutputStack::SetFirstItem(OutputBuffer *buffer) +void OutputStack::SetFirstItem(OutputBuffer *buffer) volatile { - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; if (buffer == nullptr) { // If buffer is NULL, then the first item is removed from the stack @@ -544,7 +546,7 @@ void OutputStack::SetFirstItem(OutputBuffer *buffer) } // Returns the last item from the stack or NULL if none is available -OutputBuffer *OutputStack::GetLastItem() const +OutputBuffer *OutputStack::GetLastItem() const volatile { if (count == 0) { @@ -554,11 +556,11 @@ OutputBuffer *OutputStack::GetLastItem() const } // Get the total length of all queued buffers -size_t OutputStack::DataLength() const +size_t OutputStack::DataLength() const volatile { size_t totalLength = 0; - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; for(size_t i = 0; i < count; i++) { totalLength += items[i]->Length(); @@ -569,7 +571,7 @@ size_t OutputStack::DataLength() const // Append another OutputStack to this instance. If no more space is available, // all OutputBuffers that can't be added are automatically released -void OutputStack::Append(OutputStack& stack) +void OutputStack::Append(volatile OutputStack& stack) volatile { for(size_t i = 0; i < stack.count; i++) { @@ -586,9 +588,9 @@ void OutputStack::Append(OutputStack& stack) } // Increase the number of references for each OutputBuffer on the stack -void OutputStack::IncreaseReferences(size_t num) +void OutputStack::IncreaseReferences(size_t num) volatile { - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; for(size_t i = 0; i < count; i++) { items[i]->IncreaseReferences(num); @@ -596,7 +598,7 @@ void OutputStack::IncreaseReferences(size_t num) } // Release all buffers and clean up -void OutputStack::ReleaseAll() +void OutputStack::ReleaseAll() volatile { for(size_t i = 0; i < count; i++) { diff --git a/src/OutputMemory.h b/src/OutputMemory.h index d38ab645..d060ff4e 100644 --- a/src/OutputMemory.h +++ b/src/OutputMemory.h @@ -94,9 +94,9 @@ class OutputBuffer size_t dataLength, bytesRead; bool isReferenced; - size_t references; + volatile size_t references; - static OutputBuffer * volatile freeOutputBuffers; // Messages may also be sent by ISRs, + static OutputBuffer * volatile freeOutputBuffers; // Messages may be sent by multiple tasks static volatile size_t usedOutputBuffers; // so make these volatile. static volatile size_t maxUsedOutputBuffers; }; @@ -106,49 +106,50 @@ inline uint32_t OutputBuffer::GetAge() const return millis() - whenQueued; } -// This class is used to manage references to OutputBuffer chains for all output destinations +// This class is used to manage references to OutputBuffer chains for all output destinations. +// Note that OutputStack objects should normally be declared volatile. class OutputStack { public: OutputStack() : count(0) { } // Is there anything on this stack? - bool IsEmpty() const { return count == 0; } + bool IsEmpty() const volatile { return count == 0; } // Clear the reference list - void Clear() { count = 0; } + void Clear() volatile { count = 0; } // Push an OutputBuffer chain - void Push(OutputBuffer *buffer); + void Push(OutputBuffer *buffer) volatile; // Pop an OutputBuffer chain or return NULL if none is available - OutputBuffer *Pop(); + OutputBuffer *Pop() volatile; // Returns the first item from the stack or NULL if none is available - OutputBuffer *GetFirstItem() const; + OutputBuffer *GetFirstItem() const volatile; // Set the first item of the stack. If it's NULL, then the first item will be removed - void SetFirstItem(OutputBuffer *buffer); + void SetFirstItem(OutputBuffer *buffer) volatile; // Returns the last item from the stack or NULL if none is available - OutputBuffer *GetLastItem() const; + OutputBuffer *GetLastItem() const volatile; // Get the total length of all queued buffers - size_t DataLength() const; + size_t DataLength() const volatile; // Append another OutputStack to this instance. If no more space is available, // all OutputBuffers that can't be added are automatically released - void Append(OutputStack& stack); + void Append(volatile OutputStack& stack) volatile; // Increase the number of references for each OutputBuffer on the stack - void IncreaseReferences(size_t num); + void IncreaseReferences(size_t num) volatile; // Release all buffers and clean up - void ReleaseAll(); + void ReleaseAll() volatile; private: - volatile size_t count; - OutputBuffer * volatile items[OUTPUT_STACK_DEPTH]; + size_t count; + OutputBuffer * items[OUTPUT_STACK_DEPTH]; }; #endif /* OUTPUTMEMORY_H_ */ diff --git a/src/Platform.h b/src/Platform.h index b70c875d..2cd061e4 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -821,18 +821,18 @@ private: uint32_t baudRates[NUM_SERIAL_CHANNELS]; uint8_t commsParams[NUM_SERIAL_CHANNELS]; - OutputStack auxOutput; + volatile OutputStack auxOutput; Mutex auxMutex; OutputBuffer *auxGCodeReply; // G-Code reply for AUX devices (special one because it is actually encapsulated before sending) uint32_t auxSeq; // Sequence number for AUX devices bool auxDetected; // Have we processed at least one G-Code from an AUX device? #ifdef SERIAL_AUX2_DEVICE - OutputStack aux2Output; + volatile OutputStack aux2Output; Mutex aux2Mutex; #endif - OutputStack usbOutput; + volatile OutputStack usbOutput; Mutex usbMutex; // Files diff --git a/src/RTOS work pending.txt b/src/RTOS work pending.txt index ed8a5eae..3eccaf98 100644 --- a/src/RTOS work pending.txt +++ b/src/RTOS work pending.txt @@ -28,15 +28,19 @@ Run all network responders as separate tasks? Would need mutex on network interf Bugs [done] IAP fails to update firmware -M122 output is too big for the available buffers, unless the Network task reads the output fast enough +[done I think] M122 output is too big for the available buffers, unless the Network task reads the output fast enough [probably related to above] Duet WiFi gets into a state in which it returns empty JSON messages after sending M122 from DWC. Output buffer starvation? [done] Disconnects when getting file info forCandyBowlx8comments.gcode when running RTOS build [seems better now] File upload speed is a little lower when using RTOS - may be fixed when network is a separate task [seems ok now, was probably main stack overslow] Report that Pause works, but then hangs +[done] Heater tuning crashes the firmware +[believed fixed] DWC disconnects randomly with JSON parse errors Deferred work +Use our own vsnprintf, and stop using sscanf. Should save a significant amount of stack space. +Check whether we use any time conversion functoins that use _reent SAME70 uses a different memory model i.e. not strongly-ordered. Does this have any consequences for the code so far? Are there any aspects of Platform that are not thread-safe? e.g. GCodes setting multiple interdependent variables while network reports on them? Use a mutex to protect HSMCI from reentrant calls (only needed if/when we support more than one HSMCI volume, which is unlikely but possoible on the SAME70) diff --git a/src/RTOSIface.h b/src/RTOSIface.h index a9658beb..0e7d5afd 100644 --- a/src/RTOSIface.h +++ b/src/RTOSIface.h @@ -118,32 +118,55 @@ namespace RTOSIface TaskHandle GetCurrentTask(); #ifndef RTOS - static volatile unsigned int criticalSectionNesting = 0; + static volatile unsigned int interruptCriticalSectionNesting = 0; #endif - inline void EnterCriticalSection() + // Enter a critical section, where modificatio0n to variables by interrupts (and perhaps also other tasks) must be avoided + inline void EnterInterruptCriticalSection() { #ifdef RTOS taskENTER_CRITICAL(); #else cpu_irq_disable(); - ++criticalSectionNesting; + ++interruptCriticalSectionNesting; #endif } - inline void LeaveCriticalSection() + // Leave an interrupt-critical section + inline void LeaveInterruptCriticalSection() { #ifdef RTOS taskEXIT_CRITICAL(); #else - --criticalSectionNesting; - if (criticalSectionNesting == 0) + --interruptCriticalSectionNesting; + if (interruptCriticalSectionNesting == 0) { cpu_irq_enable(); } #endif } + // Enter a task-critical region. Used to protect concurrent access to variable form different tasks, where the variable are ont used/modified by interrupts. + inline void EnterTaskCriticalSection() + { +#ifdef RTOS + vTaskSuspendAll(); +#else + // nothing to do here because there is on task preemption +#endif + } + + // Exit a task-critical region, returning true if a task switch occurred + inline bool LeaveTaskCriticalSection() + { +#ifdef RTOS + return xTaskResumeAll() == pdTRUE;; +#else + // nothing to do here because there is on task preemption + return false; +#endif + } + inline void Yield() { #ifdef RTOS @@ -152,11 +175,18 @@ namespace RTOSIface } } -class CriticalSectionLocker +class InterruptCriticalSectionLocker +{ +public: + InterruptCriticalSectionLocker() { RTOSIface::EnterInterruptCriticalSection(); } + ~InterruptCriticalSectionLocker() { (void)RTOSIface::LeaveInterruptCriticalSection(); } +}; + +class TaskCriticalSectionLocker { public: - CriticalSectionLocker() { RTOSIface::EnterCriticalSection(); } - ~CriticalSectionLocker() { RTOSIface::LeaveCriticalSection(); } + TaskCriticalSectionLocker() { RTOSIface::EnterTaskCriticalSection(); } + ~TaskCriticalSectionLocker() { RTOSIface::LeaveTaskCriticalSection(); } }; #endif /* SRC_RTOSIFACE_H_ */ diff --git a/src/Tasks.cpp b/src/Tasks.cpp index c0cc45d4..d70de1f2 100644 --- a/src/Tasks.cpp +++ b/src/Tasks.cpp @@ -28,7 +28,6 @@ constexpr unsigned int MainTaskStackWords = 2100; static Task<MainTaskStackWords> mainTask; static Mutex spiMutex; static Mutex mallocMutex; -static bool rtosRunning = false; extern "C" void MainTask(void * pvParameters); @@ -36,7 +35,7 @@ extern "C" void MainTask(void * pvParameters); // We must use a recursive mutex for it. extern "C" void __malloc_lock ( struct _reent *_r ) { - if (rtosRunning) + if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) // don't take mutex if scheduler not started or suspended { mallocMutex.Take(); } @@ -44,7 +43,7 @@ extern "C" void __malloc_lock ( struct _reent *_r ) extern "C" void __malloc_unlock ( struct _reent *_r ) { - if (rtosRunning) + if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) // don't release mutex if scheduler not started or suspended { mallocMutex.Release(); } @@ -93,8 +92,6 @@ extern "C" void AppMain() extern "C" void MainTask(void *pvParameters) { mallocMutex.Create(); - rtosRunning = true; - spiMutex.Create(); #endif reprap.Init(); diff --git a/src/Tools/Tool.cpp b/src/Tools/Tool.cpp index ab3649c2..f340d4f8 100644 --- a/src/Tools/Tool.cpp +++ b/src/Tools/Tool.cpp @@ -69,7 +69,7 @@ Tool * Tool::freelist = nullptr; Tool *t; { - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; t = freelist; if (t != nullptr) { @@ -151,7 +151,7 @@ Tool * Tool::freelist = nullptr; t->name = nullptr; t->filament = nullptr; - CriticalSectionLocker lock; + TaskCriticalSectionLocker lock; t->next = freelist; freelist = t; } diff --git a/src/Version.h b/src/Version.h index 49452175..e9fafac7 100644 --- a/src/Version.h +++ b/src/Version.h @@ -19,7 +19,7 @@ #endif #ifndef DATE -# define DATE "2018-04-04b3" +# define DATE "2018-04-05b2" #endif #define AUTHORS "reprappro, dc42, chrishamm, t3p3, dnewman" |