

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
/*! @file MemoryQueues.h
    @brief Ring-buffer message queues stored in shared memory, plus a static request/reply facility.
    @ingroup Memory

    A MessageQueue wraps a contiguous shared-memory region laid out as a
    MessageQueueHeader followed by a circular byte buffer of serialized DataMessages.
    Producers append at endPos, consumers read from startPos; cross-process signaling is
    done with named semaphores. The static API manages queues by numeric id or name so
    unrelated processes can rendezvous on the same queue.

    @note ProcessMemory.h defines its own (different, 64-bit) MessageQueueHeader used by
    the per-process queues; the two layouts are not interchangeable.
    @warning Shared-memory layouts; see MemoryManager.h for the ABI/rebuild warning. */

#if !defined(_MEMORYQUEUES_H_)
#define _MEMORYQUEUES_H_

#include "MemoryManager.h"
#include "DataMessage.h"

namespace cmlabs {

static THREAD_RET THREAD_FUNCTION_CALL QueueTest(THREAD_ARG arg);

/*! @brief On-segment header of a circular message queue (legacy 32-bit layout).
    Followed in memory by the circular data area of (size - sizeof header) bytes.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct MessageQueueHeader {
	uint32 size;		/*!< Total size of the queue region in bytes (header + buffer). */
	uint32 count;		/*!< Number of messages currently in the queue. */
	uint32 startPos;	/*!< Read offset into the circular buffer. */
	uint32 endPos;		/*!< Write offset into the circular buffer. */
	uint32 padding;		/*!< Alignment/reserved. */
};

/*! @brief Static facade over shared-memory message queues and a request/reply matcher.
    @ingroup Memory
    Queues are addressed by queue id (qid) or an optional global name. All static calls
    are safe from any process/thread; waits block on named semaphores with a timeout.
    Returned DataMessages are heap copies owned by the caller.
    @code
    uint32 qid;
    MessageQueue::CreateMessageQueue(qid, "vision.in");
    MessageQueue::AddMessageToQueue(qid, msg);            // producer process
    DataMessage* m = MessageQueue::WaitForMessageQueue(qid, 100); // consumer, 100 ms
    if (m) { ...; delete m; }
    @endcode */
class MessageQueue {
public:
	/*! Attach this wrapper to a raw queue region. @param data Mapped region. @param size Region bytes. */
	MessageQueue(char* data, uint32 size);
	~MessageQueue();

	changeSize(uint32 size);	/*!< Update the wrapper's notion of the region size. @note Missing return type — pre-C++11 implicit int; left untouched. */
	changeData(char* data);		/*!< Re-point the wrapper at a new mapped address. @note Missing return type — pre-C++11 implicit int; left untouched. */
	
	/*! Create a new shared queue. @param qid Receives the queue id. @param name Optional global name. @return true on success. */
	static bool CreateMessageQueue(uint32& qid, const char* name = NULL);
	/*! Append a message (copied into shared memory). Caller keeps ownership of @a msg. @return true on success. */
	static bool AddMessageToQueue(uint32 qid, DataMessage* msg);
	/*! Block up to @a ms milliseconds for a message. @return Heap copy owned by caller, or NULL on timeout. */
	static DataMessage* WaitForMessageQueue(uint32 qid, uint32 ms);
	/*! @return Number of messages currently queued in @a qid. */
	static uint32 GetMessageQueueSize(uint32 qid);
	/*! Look up a queue id by its global name. @return true if found. */
	static bool GetMessageQueueByName(uint32& qid, const char* name);
	/*! Destroy a queue and release its shared memory. @return true on success. */
	static bool DestroyMessageQueue(uint32 qid);

	/*! Submit a request message. @param msg Request (caller keeps ownership). @param reqID Receives the request id. @return true on success. */
	static bool AddRequest(DataMessage* msg, uint32& reqID);
	/*! Post the reply for request @a reqID. @param reqID Request id being answered. @param success Outcome flag. @param msg Reply payload (copied). @return true on success. */
	static bool AddReply(uint32 reqID, bool success, DataMessage* msg);
	/*! Block up to @a ms for the reply to @a reqID. @param reqID Request id to wait for. @param ms Timeout in ms. @param status Receives the request status.
	    @param outMsg Receives a caller-owned reply copy (may be NULL). @return true if a reply arrived. */
	static bool WaitForReply(uint32 reqID, uint32 ms, uint8& status, DataMessage** outMsg);
	/*! @return Number of requests currently outstanding. */
	static uint32 GetRequestCount();

	static bool UnitTest();			/*!< Self-test of queue + request logic. @return true if all checks pass. */
	static bool UnitTestQueues();	/*!< Self-test of the raw queue ring buffer. @return true if all checks pass. */
	friend THREAD_RET THREAD_FUNCTION_CALL QueueTest(THREAD_ARG arg);

protected:
	MessageQueueHeader* header;	/*!< Mapped queue header (points into shared memory; not owned). */
};

bool TestMemoryCommander();

} // namespace cmlabs

#endif //_MEMORYQUEUES_H_

