blob: 0ab422794ca9342624ba1d0b00a025b6e64a4b06 [file] [log] [blame]
Brian Silverman08661c72013-09-01 17:24:38 -07001#ifndef AOS_ATOM_CODE_IPC_LIB_QUEUE_H_
2#define AOS_ATOM_CODE_IPC_LIB_QUEUE_H_
brians343bc112013-02-10 01:53:46 +00003
Brian Silvermana6d1b562013-09-01 14:39:39 -07004#include "aos/atom_code/ipc_lib/shared_mem.h"
5#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 Silverman08661c72013-09-01 17:24:38 -070036 static RawQueue *Fetch(const char *name, size_t length, int hash,
Brian Silvermana6d1b562013-09-01 14:39:39 -070037 int queue_length);
38 // Same as above, except sets up the returned queue so that it will put
39 // messages on *recycle when they are freed (after they have been released by
40 // all other readers/writers and are not in the queue).
41 // recycle_queue_length determines how many freed messages will be kept.
42 // Other code can retrieve the 2 queues separately (the recycle queue will
43 // have the same length and hash as the main one). However, any frees made
44 // using a queue with only (name,length,hash,queue_length) before the
45 // recycle queue has been associated with it will not go on to the recycle
46 // queue.
47 // NOTE: calling this function with the same (name,length,hash,queue_length)
48 // but multiple recycle_queue_lengths will result in each freed message being
49 // put onto an undefined one of the recycle queues.
Brian Silverman08661c72013-09-01 17:24:38 -070050 static RawQueue *Fetch(const char *name, size_t length, int hash,
Brian Silvermana6d1b562013-09-01 14:39:39 -070051 int queue_length,
52 int recycle_hash, int recycle_queue_length,
Brian Silverman08661c72013-09-01 17:24:38 -070053 RawQueue **recycle);
brians343bc112013-02-10 01:53:46 +000054
Brian Silvermana6d1b562013-09-01 14:39:39 -070055 // Constants for passing to options arguments.
56 // The non-conflicting ones can be combined with bitwise-or.
brians343bc112013-02-10 01:53:46 +000057
Brian Silvermana6d1b562013-09-01 14:39:39 -070058 // Causes the returned message to be left in the queue.
59 // For reading only.
60 static const int kPeek = 0x0001;
61 // Reads the last message in the queue instead of just the next one.
62 // NOTE: This removes all of the messages until the last one from the queue
63 // (which means that nobody else will read them). However, PEEK means to not
64 // remove any from the queue, including the ones that are skipped.
65 // For reading only.
66 static const int kFromEnd = 0x0002;
67 // Causes reads to return NULL and writes to fail instead of waiting.
68 // For reading and writing.
69 static const int kNonBlock = 0x0004;
70 // Causes things to block.
71 // IMPORTANT: Has a value of 0 so that it is the default. This has to stay.
72 // For reading and writing.
73 static const int kBlock = 0x0000;
74 // Causes writes to overwrite the oldest message in the queue instead of
75 // blocking.
76 // For writing only.
77 static const int kOverride = 0x0008;
brians343bc112013-02-10 01:53:46 +000078
Brian Silvermana6d1b562013-09-01 14:39:39 -070079 // Writes a message into the queue.
80 // This function takes ownership of msg.
81 // NOTE: msg must point to a valid message from this queue
Brian Silverman08661c72013-09-01 17:24:38 -070082 // Returns truen on success.
Brian Silvermana6d1b562013-09-01 14:39:39 -070083 bool WriteMessage(void *msg, int options);
brians343bc112013-02-10 01:53:46 +000084
Brian Silvermana6d1b562013-09-01 14:39:39 -070085 // Reads a message out of the queue.
86 // The return value will have at least the length of this queue's worth of
87 // valid data where it's pointing to.
88 // The return value is const because other people might be viewing the same
89 // messsage. Do not cast the const away!
90 // IMPORTANT: The return value (if not NULL) must eventually be passed to
91 // FreeMessage.
92 const void *ReadMessage(int options);
93 // Exactly the same as aos_queue_read_msg, except it will never return the
94 // same message twice with the same index argument. However, it may not
95 // return some messages that pass through the queue.
96 // *index should start as 0. index does not have to be in shared memory, but
97 // it can be
98 const void *ReadMessageIndex(int options, int *index);
brians343bc112013-02-10 01:53:46 +000099
Brian Silvermana6d1b562013-09-01 14:39:39 -0700100 // Retrieves ("allocates") a message that can then be written to the queue.
101 // NOTE: the return value will be completely uninitialized
102 // The return value will have at least the length of this queue's worth of
103 // valid memory where it's pointing to.
104 // Returns NULL for error.
105 // IMPORTANT: The return value (if not NULL) must eventually be passed to
106 // FreeMessage.
107 void *GetMessage();
brians343bc112013-02-10 01:53:46 +0000108
Brian Silverman08661c72013-09-01 17:24:38 -0700109 // It is ok to call this with msg == NULL.
Brian Silvermana6d1b562013-09-01 14:39:39 -0700110 void FreeMessage(const void *msg) { DecrementMessageReferenceCount(msg); }
brians343bc112013-02-10 01:53:46 +0000111
Brian Silvermana6d1b562013-09-01 14:39:39 -0700112 private:
113 struct MessageHeader;
brians343bc112013-02-10 01:53:46 +0000114
Brian Silvermana6d1b562013-09-01 14:39:39 -0700115 // These next 4 allow finding the right one.
116 const char *name_;
117 size_t length_;
118 int hash_;
119 int queue_length_;
120 // The next one in the linked list of queues.
Brian Silverman08661c72013-09-01 17:24:38 -0700121 RawQueue *next_;
brians343bc112013-02-10 01:53:46 +0000122
Brian Silverman08661c72013-09-01 17:24:38 -0700123 RawQueue *recycle_;
Brian Silvermana6d1b562013-09-01 14:39:39 -0700124
125 Mutex data_lock_; // protects operations on data_ etc
126 Condition readable_;
127 Condition writable_;
128 int data_length_; // max length into data + 1
129 int data_start_; // is an index into data
130 int data_end_; // is an index into data
131 int messages_; // that have passed through
132 void **data_; // array of messages (with headers)
133
134 Mutex pool_lock_;
135 size_t msg_length_; // sizeof(each message) including the header
136 int mem_length_; // the max number of messages that will ever be allocated
137 int messages_used_;
138 int pool_length_; // the number of allocated messages
139 MessageHeader **pool_; // array of pointers to messages
140
141 // Actually frees the given message.
142 void DoFreeMessage(const void *msg);
143 // Calls DoFreeMessage if appropriate.
144 void DecrementMessageReferenceCount(const void *msg);
145
146 // Should be called with data_lock_ locked.
147 // Returns with a readable message in data_ or false.
148 bool ReadCommonStart(int options, int *index);
149 // Deals with setting/unsetting readable_ and writable_.
150 // Should be called after data_lock_ has been unlocked.
151 // read is whether or not this read call read one off the queue
152 void ReadCommonEnd(bool read);
153 // Handles reading with kPeek.
154 void *ReadPeek(int options, int start);
155
156 // Gets called by Fetch when necessary (with placement new).
Brian Silverman08661c72013-09-01 17:24:38 -0700157 RawQueue(const char *name, size_t length, int hash, int queue_length);
Brian Silvermana6d1b562013-09-01 14:39:39 -0700158};
159
160} // namespace aos
161
Brian Silverman08661c72013-09-01 17:24:38 -0700162#endif // AOS_ATOM_CODE_IPC_LIB_QUEUE_H_