Brian Silverman | 14fd0fb | 2014-01-14 21:42:01 -0800 | [diff] [blame] | 1 | #ifndef AOS_LINUX_CODE_IPC_LIB_QUEUE_H_ |
| 2 | #define AOS_LINUX_CODE_IPC_LIB_QUEUE_H_ |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 3 | |
Brian Silverman | 14fd0fb | 2014-01-14 21:42:01 -0800 | [diff] [blame] | 4 | #include "aos/linux_code/ipc_lib/shared_mem.h" |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 5 | #include "aos/common/mutex.h" |
| 6 | #include "aos/common/condition.h" |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 7 | |
| 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 | |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 13 | // 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 Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 16 | // (FreeMessage and WriteMessage are common ones) or the |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 17 | // application will leak shared memory. |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 18 | // NOTE: Taking a message from ReadMessage and then passing it to WriteMessage |
| 19 | // might work, but it is not guaranteed to. |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 20 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 21 | namespace aos { |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 22 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 23 | // 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 Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 29 | class RawQueue { |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 30 | 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 Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 36 | static RawQueue *Fetch(const char *name, size_t length, int hash, |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 37 | 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 Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 50 | static RawQueue *Fetch(const char *name, size_t length, int hash, |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 51 | int queue_length, |
| 52 | int recycle_hash, int recycle_queue_length, |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 53 | RawQueue **recycle); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 54 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 55 | // Constants for passing to options arguments. |
| 56 | // The non-conflicting ones can be combined with bitwise-or. |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 57 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 58 | // 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; |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 78 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 79 | // 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 Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 82 | // Returns truen on success. |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 83 | bool WriteMessage(void *msg, int options); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 84 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 85 | // 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); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 99 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 100 | // 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(); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 108 | |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 109 | // It is ok to call this method with a NULL msg. |
| 110 | void FreeMessage(const void *msg) { |
| 111 | if (msg != NULL) DecrementMessageReferenceCount(msg); |
| 112 | } |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 113 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 114 | private: |
| 115 | struct MessageHeader; |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 116 | struct ReadData; |
| 117 | |
| 118 | bool is_readable() { return data_end_ != data_start_; } |
| 119 | bool is_writable() { return ((data_end_ + 1) % data_length_) != data_start_; } |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 120 | |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 121 | // These next 4 allow finding the right one. |
| 122 | const char *name_; |
| 123 | size_t length_; |
| 124 | int hash_; |
| 125 | int queue_length_; |
| 126 | // The next one in the linked list of queues. |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 127 | RawQueue *next_; |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 128 | |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 129 | RawQueue *recycle_; |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 130 | |
| 131 | Mutex data_lock_; // protects operations on data_ etc |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 132 | // Always gets broadcasted to because different readers might have different |
| 133 | // ideas of what "readable" means (ie ones using separated indices). |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 134 | Condition readable_; |
| 135 | Condition writable_; |
| 136 | int data_length_; // max length into data + 1 |
| 137 | int data_start_; // is an index into data |
| 138 | int data_end_; // is an index into data |
| 139 | int messages_; // that have passed through |
| 140 | void **data_; // array of messages (with headers) |
| 141 | |
| 142 | Mutex pool_lock_; |
| 143 | size_t msg_length_; // sizeof(each message) including the header |
| 144 | int mem_length_; // the max number of messages that will ever be allocated |
| 145 | int messages_used_; |
| 146 | int pool_length_; // the number of allocated messages |
| 147 | MessageHeader **pool_; // array of pointers to messages |
| 148 | |
| 149 | // Actually frees the given message. |
| 150 | void DoFreeMessage(const void *msg); |
| 151 | // Calls DoFreeMessage if appropriate. |
| 152 | void DecrementMessageReferenceCount(const void *msg); |
| 153 | |
| 154 | // Should be called with data_lock_ locked. |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 155 | // *read_data will be initialized. |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 156 | // Returns with a readable message in data_ or false. |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 157 | bool ReadCommonStart(int options, int *index, ReadData *read_data); |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 158 | // Deals with setting/unsetting readable_ and writable_. |
| 159 | // Should be called after data_lock_ has been unlocked. |
Brian Silverman | 797e71e | 2013-09-06 17:29:39 -0700 | [diff] [blame] | 160 | // read_data should be the same thing that was passed in to ReadCommonStart. |
| 161 | void ReadCommonEnd(ReadData *read_data); |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 162 | // Handles reading with kPeek. |
| 163 | void *ReadPeek(int options, int start); |
| 164 | |
| 165 | // Gets called by Fetch when necessary (with placement new). |
Brian Silverman | 08661c7 | 2013-09-01 17:24:38 -0700 | [diff] [blame] | 166 | RawQueue(const char *name, size_t length, int hash, int queue_length); |
Brian Silverman | a6d1b56 | 2013-09-01 14:39:39 -0700 | [diff] [blame] | 167 | }; |
| 168 | |
| 169 | } // namespace aos |
| 170 | |
Brian Silverman | 14fd0fb | 2014-01-14 21:42:01 -0800 | [diff] [blame] | 171 | #endif // AOS_LINUX_CODE_IPC_LIB_QUEUE_H_ |