blob: 45609ab07c61487d023978b21ab77f447494882d [file] [log] [blame]
Brian Silverman14fd0fb2014-01-14 21:42:01 -08001#ifndef AOS_LINUX_CODE_IPC_LIB_QUEUE_H_
2#define AOS_LINUX_CODE_IPC_LIB_QUEUE_H_
brians343bc112013-02-10 01:53:46 +00003
Brian Silverman14fd0fb2014-01-14 21:42:01 -08004#include "aos/linux_code/ipc_lib/shared_mem.h"
Brian Silvermana6d1b562013-09-01 14:39:39 -07005#include "aos/common/mutex.h"
6#include "aos/common/condition.h"
brians343bc112013-02-10 01:53:46 +00007
8// TODO(brians) add valgrind client requests to the queue and shared_mem_malloc
9// code to make checking for leaks work better
10// <http://www.valgrind.org/docs/manual/mc-manual.html#mc-manual.mempools>
11// describes how
12
brians343bc112013-02-10 01:53:46 +000013// Any pointers returned from these functions can be safely passed to other
14// processes because they are all shared memory pointers.
15// IMPORTANT: Any message pointer must be passed back in some way
Brian Silvermana6d1b562013-09-01 14:39:39 -070016// (FreeMessage and WriteMessage are common ones) or the
brians343bc112013-02-10 01:53:46 +000017// application will leak shared memory.
Brian Silvermana6d1b562013-09-01 14:39:39 -070018// NOTE: Taking a message from ReadMessage and then passing it to WriteMessage
19// might work, but it is not guaranteed to.
brians343bc112013-02-10 01:53:46 +000020
Brian Silvermana6d1b562013-09-01 14:39:39 -070021namespace aos {
brians343bc112013-02-10 01:53:46 +000022
Brian Silvermana6d1b562013-09-01 14:39:39 -070023// Queues are the primary way to use shared memory. Basic use consists of
24// calling Queue::Fetch and then reading and/or writing messages.
25// Queues (as the name suggests) are a FIFO stack of messages. Each combination
26// of name and type signature will result in a different queue, which means
27// that if you only recompile some code that uses differently sized messages,
28// it will simply use a different queue than the old code.
Brian Silverman08661c72013-09-01 17:24:38 -070029class RawQueue {
Brian Silvermana6d1b562013-09-01 14:39:39 -070030 public:
31 // Retrieves (and creates if necessary) a queue. Each combination of name and
32 // signature refers to a completely independent queue.
33 // length is how large each message will be
34 // hash can differentiate multiple otherwise identical queues
35 // queue_length is how many messages the queue will be able to hold
Brian Silverman227ad482014-03-23 11:21:32 -070036 // Will never return NULL.
Brian Silverman08661c72013-09-01 17:24:38 -070037 static RawQueue *Fetch(const char *name, size_t length, int hash,
Brian Silvermana6d1b562013-09-01 14:39:39 -070038 int queue_length);
39 // Same as above, except sets up the returned queue so that it will put
40 // messages on *recycle when they are freed (after they have been released by
41 // all other readers/writers and are not in the queue).
42 // recycle_queue_length determines how many freed messages will be kept.
43 // Other code can retrieve the 2 queues separately (the recycle queue will
44 // have the same length and hash as the main one). However, any frees made
45 // using a queue with only (name,length,hash,queue_length) before the
46 // recycle queue has been associated with it will not go on to the recycle
47 // queue.
48 // NOTE: calling this function with the same (name,length,hash,queue_length)
49 // but multiple recycle_queue_lengths will result in each freed message being
50 // put onto an undefined one of the recycle queues.
Brian Silverman227ad482014-03-23 11:21:32 -070051 // Will never return NULL.
Brian Silverman08661c72013-09-01 17:24:38 -070052 static RawQueue *Fetch(const char *name, size_t length, int hash,
Brian Silvermana6d1b562013-09-01 14:39:39 -070053 int queue_length,
54 int recycle_hash, int recycle_queue_length,
Brian Silverman08661c72013-09-01 17:24:38 -070055 RawQueue **recycle);
brians343bc112013-02-10 01:53:46 +000056
Brian Silvermana6d1b562013-09-01 14:39:39 -070057 // Constants for passing to options arguments.
58 // The non-conflicting ones can be combined with bitwise-or.
brians343bc112013-02-10 01:53:46 +000059
Brian Silvermaneb51cbb2014-03-14 22:57:08 -070060 // Doesn't update the currently read index (the read messages in the queue or
61 // the index). This means the returned message (and any others skipped with
62 // kFromEnd) will be left in the queue.
Brian Silvermana6d1b562013-09-01 14:39:39 -070063 // For reading only.
64 static const int kPeek = 0x0001;
65 // Reads the last message in the queue instead of just the next one.
66 // NOTE: This removes all of the messages until the last one from the queue
Brian Silvermaneb51cbb2014-03-14 22:57:08 -070067 // (which means that nobody else will read them).
Brian Silvermana6d1b562013-09-01 14:39:39 -070068 // For reading only.
69 static const int kFromEnd = 0x0002;
70 // Causes reads to return NULL and writes to fail instead of waiting.
71 // For reading and writing.
72 static const int kNonBlock = 0x0004;
73 // Causes things to block.
Brian Silvermaneb51cbb2014-03-14 22:57:08 -070074 // IMPORTANT: Has a value of 0 so that it is the default. This has to stay
75 // this way.
Brian Silvermana6d1b562013-09-01 14:39:39 -070076 // For reading and writing.
77 static const int kBlock = 0x0000;
78 // Causes writes to overwrite the oldest message in the queue instead of
79 // blocking.
80 // For writing only.
81 static const int kOverride = 0x0008;
brians343bc112013-02-10 01:53:46 +000082
Brian Silvermana6d1b562013-09-01 14:39:39 -070083 // Writes a message into the queue.
84 // This function takes ownership of msg.
85 // NOTE: msg must point to a valid message from this queue
Brian Silverman227ad482014-03-23 11:21:32 -070086 // Returns true on success. A return value of false means msg has already been
87 // freed.
Brian Silvermana6d1b562013-09-01 14:39:39 -070088 bool WriteMessage(void *msg, int options);
brians343bc112013-02-10 01:53:46 +000089
Brian Silvermana6d1b562013-09-01 14:39:39 -070090 // Reads a message out of the queue.
91 // The return value will have at least the length of this queue's worth of
92 // valid data where it's pointing to.
93 // The return value is const because other people might be viewing the same
94 // messsage. Do not cast the const away!
95 // IMPORTANT: The return value (if not NULL) must eventually be passed to
96 // FreeMessage.
97 const void *ReadMessage(int options);
Brian Silverman227ad482014-03-23 11:21:32 -070098 // The same as ReadMessage, except it will never return the
99 // same message twice (when used with the same index argument). However,
100 // may not return some messages that pass through the queue.
Brian Silvermana6d1b562013-09-01 14:39:39 -0700101 // *index should start as 0. index does not have to be in shared memory, but
Brian Silvermancd2d84c2014-03-13 23:30:58 -0700102 // it can be.
Brian Silvermana6d1b562013-09-01 14:39:39 -0700103 const void *ReadMessageIndex(int options, int *index);
brians343bc112013-02-10 01:53:46 +0000104
Brian Silvermana6d1b562013-09-01 14:39:39 -0700105 // Retrieves ("allocates") a message that can then be written to the queue.
106 // NOTE: the return value will be completely uninitialized
107 // The return value will have at least the length of this queue's worth of
108 // valid memory where it's pointing to.
109 // Returns NULL for error.
110 // IMPORTANT: The return value (if not NULL) must eventually be passed to
Brian Silverman227ad482014-03-23 11:21:32 -0700111 // FreeMessage or WriteMessage.
Brian Silvermana6d1b562013-09-01 14:39:39 -0700112 void *GetMessage();
brians343bc112013-02-10 01:53:46 +0000113
Brian Silverman797e71e2013-09-06 17:29:39 -0700114 // It is ok to call this method with a NULL msg.
115 void FreeMessage(const void *msg) {
116 if (msg != NULL) DecrementMessageReferenceCount(msg);
117 }
brians343bc112013-02-10 01:53:46 +0000118
Brian Silvermanc2e04222014-03-22 12:43:44 -0700119 // UNSAFE! Returns the number of free messages we have. Only safe to use when
120 // only 1 task is using this object (ie in tests).
121 int FreeMessages() const;
Brian Silvermaneb51cbb2014-03-14 22:57:08 -0700122
Brian Silvermana6d1b562013-09-01 14:39:39 -0700123 private:
124 struct MessageHeader;
Brian Silverman797e71e2013-09-06 17:29:39 -0700125 struct ReadData;
126
127 bool is_readable() { return data_end_ != data_start_; }
128 bool is_writable() { return ((data_end_ + 1) % data_length_) != data_start_; }
brians343bc112013-02-10 01:53:46 +0000129
Brian Silvermana6d1b562013-09-01 14:39:39 -0700130 // These next 4 allow finding the right one.
131 const char *name_;
132 size_t length_;
133 int hash_;
134 int queue_length_;
135 // The next one in the linked list of queues.
Brian Silverman08661c72013-09-01 17:24:38 -0700136 RawQueue *next_;
brians343bc112013-02-10 01:53:46 +0000137
Brian Silverman08661c72013-09-01 17:24:38 -0700138 RawQueue *recycle_;
Brian Silvermana6d1b562013-09-01 14:39:39 -0700139
140 Mutex data_lock_; // protects operations on data_ etc
Brian Silverman797e71e2013-09-06 17:29:39 -0700141 // Always gets broadcasted to because different readers might have different
142 // ideas of what "readable" means (ie ones using separated indices).
Brian Silvermana6d1b562013-09-01 14:39:39 -0700143 Condition readable_;
144 Condition writable_;
145 int data_length_; // max length into data + 1
146 int data_start_; // is an index into data
147 int data_end_; // is an index into data
148 int messages_; // that have passed through
149 void **data_; // array of messages (with headers)
150
Brian Silvermana6d1b562013-09-01 14:39:39 -0700151 size_t msg_length_; // sizeof(each message) including the header
Brian Silvermanc2e04222014-03-22 12:43:44 -0700152 // A pointer to the first in the linked list of free messages.
153 MessageHeader *free_messages_;
Brian Silvermana6d1b562013-09-01 14:39:39 -0700154
155 // Actually frees the given message.
156 void DoFreeMessage(const void *msg);
157 // Calls DoFreeMessage if appropriate.
158 void DecrementMessageReferenceCount(const void *msg);
Brian Silverman430e7fa2014-03-21 16:58:33 -0700159 // Only does the actual incrementing of the reference count.
160 void IncrementMessageReferenceCount(const void *msg) const;
Brian Silvermana6d1b562013-09-01 14:39:39 -0700161
Brian Silvermaneb51cbb2014-03-14 22:57:08 -0700162 // Must be called with data_lock_ locked.
Brian Silverman797e71e2013-09-06 17:29:39 -0700163 // *read_data will be initialized.
Brian Silvermana6d1b562013-09-01 14:39:39 -0700164 // Returns with a readable message in data_ or false.
Brian Silverman797e71e2013-09-06 17:29:39 -0700165 bool ReadCommonStart(int options, int *index, ReadData *read_data);
Brian Silvermana6d1b562013-09-01 14:39:39 -0700166 // Deals with setting/unsetting readable_ and writable_.
Brian Silvermaneb51cbb2014-03-14 22:57:08 -0700167 // Must be called after data_lock_ has been unlocked.
Brian Silverman797e71e2013-09-06 17:29:39 -0700168 // read_data should be the same thing that was passed in to ReadCommonStart.
169 void ReadCommonEnd(ReadData *read_data);
Brian Silverman227ad482014-03-23 11:21:32 -0700170 // Returns the index of the last message.
171 // Useful for reading with kPeek.
172 int LastMessageIndex() const;
Brian Silvermana6d1b562013-09-01 14:39:39 -0700173
174 // Gets called by Fetch when necessary (with placement new).
Brian Silverman08661c72013-09-01 17:24:38 -0700175 RawQueue(const char *name, size_t length, int hash, int queue_length);
Brian Silvermana6d1b562013-09-01 14:39:39 -0700176};
177
178} // namespace aos
179
Brian Silverman14fd0fb2014-01-14 21:42:01 -0800180#endif // AOS_LINUX_CODE_IPC_LIB_QUEUE_H_