+/** Allocate a message buffer large enough to hold \a length bytes.
+ * TODO: \a in_mb needs better documentation.
+ * @param[in] in_mb Some other message buffer(?).
+ * @param[in] length Number of bytes of space to reserve in output.
+ * @return Pointer to some usable message buffer.
+ */
+static struct MsgBuf *
+msgq_alloc(struct MsgBuf *in_mb, int length)
+{
+ struct MsgBuf *mb;
+ int power;
+
+ /* Find the power of two size that will accommodate the message */
+ for (power = MB_BASE_SHIFT; power < MB_MAX_SHIFT + 1; power++)
+ if ((length - 1) >> power == 0)
+ break;
+ assert((1 << power) >= length);
+ assert((1 << power) <= 512);
+ length = 1 << power; /* reset the length */
+
+ /* If the message needs a buffer of exactly the existing size, just use it */
+ if (in_mb && in_mb->power == power) {
+ in_mb->real = in_mb; /* real buffer is this buffer */
+ return in_mb;
+ }
+
+ /* Try popping one off the freelist first */
+ if ((mb = MQData.msgBufs[power - MB_BASE_SHIFT].free)) {
+ MQData.msgBufs[power - MB_BASE_SHIFT].free = mb->next;
+ } else if (MQData.tot_bufsize < feature_int(FEAT_BUFFERPOOL)) {
+ /* Allocate another if we won't bust the BUFFERPOOL */
+ Debug((DEBUG_MALLOC, "Allocating MsgBuf of length %d (total size %zu)",
+ length, sizeof(struct MsgBuf) + length));
+ mb = (struct MsgBuf *)MyMalloc(sizeof(struct MsgBuf) + length);
+ MQData.msgBufs[power - MB_BASE_SHIFT].alloc++;
+ mb->power = power; /* remember size */
+ MQData.tot_bufsize += length;
+ }
+
+ if (mb) {
+ MQData.msgBufs[power - MB_BASE_SHIFT].used++; /* how many are we using? */
+
+ mb->real = 0; /* essential initializations */
+ mb->ref = 1;
+
+ if (in_mb) /* remember who's the *real* buffer */
+ in_mb->real = mb;
+ } else if (in_mb) /* just use the input buffer */
+ mb = in_mb->real = in_mb;
+
+ return mb; /* return the buffer */
+}
+
+/** Deallocate unused message buffers.
+ */
+static void
+msgq_clear_freembs(void)
+{
+ struct MsgBuf *mb;
+ int i;
+
+ /* Walk through the various size classes */
+ for (i = MB_BASE_SHIFT; i < MB_MAX_SHIFT + 1; i++)
+ /* walk down the free list */
+ while ((mb = MQData.msgBufs[i - MB_BASE_SHIFT].free)) {
+ MQData.msgBufs[i - MB_BASE_SHIFT].free = mb->next; /* shift free list */
+ MQData.msgBufs[i - MB_BASE_SHIFT].alloc--; /* reduce allocation count */
+ MQData.tot_bufsize -= 1 << i; /* reduce total buffer allocation count */
+ MyFree(mb); /* and free the buffer */
+ }
+}
+
+/** Format a message buffer for a client from a format string.
+ * @param[in] dest %Client that receives the data (may be NULL).
+ * @param[in] format Format string for message.
+ * @param[in] vl Argument list for \a format.
+ * @return Allocated MsgBuf.