Garbage Collector Causing Networking.dll Exception

Hi, I’m running into an interesting issue where I get an an unhandled exception from the Networking.dll file. The exception gets triggered after manually calling the garbage collector and looks like this:

#### Exception System.ObjectDisposedException - 0x00000000 (13) ####
    #### Message: 
    #### System.Net.Sockets.NetworkStream::get_Length [IP: 0009] ####
    #### System.Net.InputNetworkStreamWrapper::Read_HTTP_Line [IP: 004b] ####
    #### System.Net.HttpListenerRequest::ParseHTTPRequest [IP: 000d] ####
    #### System.Net.HttpListenerContext::get_Response [IP: 000d] ####
An unhandled exception of type 'System.ObjectDisposedException' occurred in GHIElectronics.TinyCLR.Networking.dll

I have an HTTP server running in the background and this exception will only trigger after I have made an HTTP request from my PC. I’m wondering if I’m not destroying an object properly so here is a sample of my HTTP server setup (running on its own thread):

        ///<summary> Async listener task. </summary>
        private void HttpServerTask()
        {
            try
            {
                //Verify the previous HTTP connection is closed
                if (_httpListener != null)
                {
                    StopHttpServer();
                }

                Logger.LogMessage(Logger.Level.Info, _controllerId, $"Opening new HTTP server (IP: {EthernetController.GetIpAddressString()}, Port: 80)...");
                _stopListening = false;

                //Start a new HTTP listener
                _httpListener = new HttpListener("http", 80); //http = 80, https = 443
                _httpListener.Start();
                int totalRequests = 0;

                //Continuously listen until the network connection is closed
                while (_httpListener != null && _httpListener.IsListening && !_stopListening && EthernetController.IsInitialized && EthernetController.LinkReady)
                {
                    //Close any previous connections and wait for a new request (blocking)
                    _clientConnection?.Request?.Reset();
                    _clientConnection?.Response?.Close();
                    _clientConnection?.Reset();
                    _clientConnection = null;
                    _clientConnection = _httpListener.GetContext();

                    //Increment the total number of requests
                    totalRequests++;
                    Logger.LogMessage(Logger.Level.Debug, _controllerId, $"New request received from {_clientConnection.Request.RemoteEndPoint.Address}. Total session requests: {totalRequests}.");
                    Logger.LogMessage(Logger.Level.Debug, _controllerId, $"URL request: {EthernetController.GetIpAddressString()}{_clientConnection.Request.RawUrl}");
                    EthernetController.NetworkIsHealthy();

                    //Invoke the request received event
                    OnHttpRequestReceived.Invoke(_clientConnection.Request.RemoteEndPoint.Address, _clientConnection.Request.RawUrl.TrimEnd('/'));
                }
            }
            catch (Exception ex)
            { 
                //If the listener was not manually shut down, and the network is still available, restart the server end the current thread
                if (!_stopListening && EthernetController.LinkReady)
                {
                    Logger.LogMessage(Logger.Level.Error, _controllerId, $"HttpServerTask() failed - {ex.Message}.\r");
                    new Thread(StartHttpServer).Start();
                }
            }
        }

Another exception in my SD card class! I’m wondering if running the garbage collector is causing problems :thinking:… Note: I am using an SC20260D with extended heap.

SD Write Function:

        public static bool WriteToFile(string filePath, byte[] dataToWrite, int offsetIndex, int numBytesToWrite)
        {
            try
            {
                //Check the SD card status
                if (!SdCardIsAvailable())
                {
                    Logger.LogMessage(Logger.Level.Warning, ControllerId, "WriteToFile() failed - SD card is not available.");
                    return false;
                }

                //Format the file path
                string formattedPath = FormatFilePath(filePath);

                //If the file to write should be within a directory, make sure the directory exists
                if (!Directory.Exists(ExtractParentPath(formattedPath, '\\')))
                {
                    Directory.CreateDirectory(ExtractParentPath(formattedPath, '\\'));
                }

                //If the data is empty, return true
                if (dataToWrite == null || dataToWrite.Length == 0)
                {
                    return true;
                }

                //Lock the thread while writing
                lock (ThreadLock)
                {
                    //Write the data to the file
                    using (FileStream writeStream = new FileStream(formattedPath, FileMode.Append))
                    {
                        writeStream.Write(dataToWrite, offsetIndex, numBytesToWrite); // <--- This line eventually causes final exceptions
                        writeStream.Flush(); // <--- This line hangs for 8-10 seconds
                        FileSystem.Flush(_sdCardController.Hdc);
                        writeStream.Close();
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                _sdCardIsConnected = false;
                Logger.LogMessage(Logger.Level.Error, ControllerId, $"WriteToFile() failed - {ex.Message}, {ex.InnerException}, {ex.StackTrace}.\r");
                _sdCardIsConnected = true;
                return false;
            }
        }

After running the program for a while the WriteToFile() function speed suddenly screeches to a halt–specifically, the writeStream.Flush() line takes like 8-10 seconds to execute and this exception will get called exactly once when the slow down starts:

#### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (15) ####
    #### Message: 
    #### System.IO.FileStream::get_CanSeek [IP: 0007] ####
 Uncaught exception 
    #### Exception System.NullReferenceException - CLR_E_NULL_REFERENCE (16) ####
    #### Message: 
    #### System.IO.FileStream::get_CanWrite [IP: 0013] ####
 Uncaught exception 
    #### Exception System.ObjectDisposedException - 0x00000000 (18) ####
    #### Message: 
    #### System.IO.FileStream::get_Length [IP: 0009] ####
 Uncaught exception 
    #### Exception System.ObjectDisposedException - 0x00000000 (20) ####
    #### Message: 
    #### System.IO.FileStream::get_Position [IP: 0009] ####
 Uncaught exception

Then, after about 10 minutes, the try catch will get triggered from the writeStream.Write() function and this exception will be displayed:

#### Exception System.InvalidOperationException - CLR_E_INVALID_OPERATION (1) ####
    #### Message: 
    #### GHIElectronics.TinyCLR.IO.FileSystem+NativeFileStream::Write [IP: 0000] ####
    #### System.IO.FileStream::Write [IP: 0041] ####
    #### GHI_Framework.SdCardController::WriteToFile [IP: 0071] ####
    #### GHI_Framework.SdCardController::WriteLogToSdCard [IP: 00b0] ####
    #### GHI_Framework.Logger::LogMessage [IP: 010d] ####
    #### GHI_Framework.SystemHealthManager::CheckSystemHealth [IP: 00b4] ####
    #### JBM_200.MainApp::Main [IP: 01af] ####
Exception thrown: 'System.InvalidOperationException' in GHIElectronics.TinyCLR.IO.dll

For the SDCard issue, we seen some SDCards aren’t happy with 24MHz. Try to slower the speed.

// GHI added – set SD clock. Using divider.
const int SD_CLOCK_ADDRESS_REG = 0x00000004;
var clock_divider = 2; // give 24 / 2 = 12MHz
 
// div 1: 24 / 1 = 24 MHz
// div 2: 24 / 2 = 12 MHz
// div 3: 24 / 3 = 8 MHz
// div 4: 24 / 4 = 6 MHz
// div 5: 24 / 5 = 4.8 MHz
// div 6: 24 / 6 = 4 MHz
   …..
 
// Setting clock need to be before initialize/mount SDcard
Marshal.WriteInt32((IntPtr)SD_CLOCK_ADDRESS_REG, clock_divider);
 
// Initialize / mount SDCard
var sd = GHIElectronics.TinyCLR.Devices.Storage.StorageController.FromName(GHIElectronics.TinyCLR.Pins.SC20260.StorageController.SdCard);
var drive = GHIElectronics.TinyCLR.IO.FileSystem.Mount(sd.Hdc);   

Added that line to the SD class and letting it run, so far no problems with the write function but will keep updated. Still having the HTTP/.dll exception though :face_exhaling:

Could you post to github this issue, include sample if you can, more detail to help us to reproduce, help us to fix it faster, you know

1 Like

Git Post + sample project:

1 Like

Looks like dividing the clock did not fix the SD card issue. Tried dividing by 2 and by 3, both still had the same results :frowning:

what kind of the sd card are you using?

Centon 16GB Micro SD Card, not sure about specific P/N

We correct GC exception issue but seem your code doesn’t include SD exception issue? If you can send it again we can take a look.

Thank you!
I did some digging and I think it might be a visual studio setting called “Just My Code”? I must have enabled or disabled it at some point, or some other setting to be able to have the internal exception thrown while in debug mode. The code seems to run okay when not running in debug… :thinking:

Try 2.3.0.1000: Downloads (ghielectronics.com)