1 /* 2 * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33 /* 34 * This utility provides a sliding receive window implementation. It uses a 35 * circular queue to order incoming messages based on the message ID in the 36 * transport protocol. 37 */ 38 39 #if !defined(FI_RECVWIN_H) 40 #define FI_RECVWIN_H 41 42 #include "config.h" 43 44 #include <assert.h> 45 #include <stdlib.h> 46 #include <stdio.h> 47 #include <unistd.h> 48 #include <fcntl.h> 49 #include <ofi.h> 50 #include <ofi_rbuf.h> 51 52 #define OFI_DECL_RECVWIN_BUF(entrytype, name, id_type) \ 53 OFI_DECLARE_CIRQUE(entrytype, recvwin_cirq); \ 54 struct name { \ 55 id_type exp_msg_id; \ 56 id_type win_size; \ 57 struct recvwin_cirq *pending; \ 58 }; \ 59 \ 60 static inline struct name * \ 61 ofi_recvwin_buf_alloc(struct name *recvq, unsigned int size) \ 62 { \ 63 assert(size == roundup_power_of_two(size)); \ 64 recvq->exp_msg_id = 0; \ 65 recvq->win_size = size; \ 66 recvq->pending = recvwin_cirq_create(recvq->win_size); \ 67 return recvq; \ 68 } \ 69 \ 70 static inline void \ 71 ofi_recvwin_free(struct name *recvq) \ 72 { \ 73 recvwin_cirq_free(recvq->pending); \ 74 } \ 75 \ 76 static inline int \ 77 ofi_recvwin_id_valid(struct name *recvq, id_type id) \ 78 { \ 79 return ofi_recvwin_id_valid_ ## id_type (recvq, id); \ 80 } \ 81 \ 82 static inline int \ 83 ofi_recvwin_queue_msg(struct name *recvq, entrytype * msg, id_type id) \ 84 { \ 85 size_t write_idx; \ 86 \ 87 assert(ofi_recvwin_id_valid(recvq, id)); \ 88 write_idx = (ofi_cirque_rindex(recvq->pending) \ 89 + (id - recvq->exp_msg_id)) \ 90 & recvq->pending->size_mask; \ 91 recvq->pending->buf[write_idx] = *msg; \ 92 ofi_cirque_commit(recvq->pending); \ 93 return 0; \ 94 } \ 95 \ 96 static inline entrytype * \ 97 ofi_recvwin_get_msg(struct name *recvq, id_type id) \ 98 { \ 99 size_t read_idx; \ 100 \ 101 assert(ofi_recvwin_id_valid(recvq, id)); \ 102 read_idx = (ofi_cirque_rindex(recvq->pending) \ 103 + (id - recvq->exp_msg_id)) \ 104 & recvq->pending->size_mask; \ 105 return &recvq->pending->buf[read_idx]; \ 106 } \ 107 \ 108 static inline entrytype * \ 109 ofi_recvwin_get_next_msg(struct name *recvq) \ 110 { \ 111 if (ofi_cirque_head(recvq->pending)) { \ 112 ofi_recvwin_exp_inc(recvq); \ 113 return ofi_cirque_remove(recvq->pending); \ 114 } else { \ 115 return NULL; \ 116 } \ 117 } \ 118 \ 119 static inline void \ 120 ofi_recvwin_slide(struct name *recvq) \ 121 { \ 122 ofi_recvwin_exp_inc(recvq); \ 123 ofi_cirque_discard(recvq->pending); \ 124 ofi_cirque_commit(recvq->pending); \ 125 } 126 127 #define ofi_recvwin_peek(rq) (ofi_cirque_head(rq->pending)) 128 #define ofi_recvwin_is_empty(rq) (ofi_cirque_isempty(rq->pending)) 129 #define ofi_recvwin_exp_inc(rq) ((rq)->exp_msg_id++) 130 #define ofi_recvwin_is_exp(rq, id) ((rq)->exp_msg_id == id) 131 #define ofi_recvwin_next_exp_id(rq) ((rq)->exp_msg_id) 132 /* 133 * When exp_msg_id on the receiver has not wrapped around but the sender ID has 134 * we need to allow the IDs starting from 0 that are valid. These macros use 135 * the overflow of exp_msg_id to validate that. 136 */ 137 #define ofi_recvwin_id_valid_uint32_t(rq, id) \ 138 ofi_val32_inrange(rq->exp_msg_id, rq->win_size, id) 139 #define ofi_recvwin_id_valid_uint64_t(rq, id) \ 140 ofi_val64_inrange(rq->exp_msg_id, rq->win_size, id) 141 142 #endif /* FI_RECVWIN_H */ 143