1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov/* 350aadb33SDmitri Tikhonov * lsquic_spi.c - implementation of Stream Priority Iterator. 450aadb33SDmitri Tikhonov */ 550aadb33SDmitri Tikhonov 650aadb33SDmitri Tikhonov#include <assert.h> 750aadb33SDmitri Tikhonov#include <inttypes.h> 850aadb33SDmitri Tikhonov#include <stdint.h> 950aadb33SDmitri Tikhonov#include <stdlib.h> 10c51ce338SDmitri Tikhonov#include <string.h> 1150aadb33SDmitri Tikhonov#include <sys/queue.h> 1250aadb33SDmitri Tikhonov#include <sys/types.h> 13461e84d8SAmol Deshpande#ifdef WIN32 14461e84d8SAmol Deshpande#include <vc_compat.h> 15461e84d8SAmol Deshpande#endif 1650aadb33SDmitri Tikhonov 1750aadb33SDmitri Tikhonov#include "lsquic_types.h" 1850aadb33SDmitri Tikhonov#include "lsquic_int_types.h" 1950aadb33SDmitri Tikhonov#include "lsquic_sfcw.h" 205392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 215392f7a3SLiteSpeed Tech#include "lsquic_hq.h" 225392f7a3SLiteSpeed Tech#include "lsquic_hash.h" 2350aadb33SDmitri Tikhonov#include "lsquic_stream.h" 24fbc6cc04SDmitri Tikhonov#include "lsquic_conn_flow.h" 25fbc6cc04SDmitri Tikhonov#include "lsquic_rtt.h" 26fbc6cc04SDmitri Tikhonov#include "lsquic_conn_public.h" 2750aadb33SDmitri Tikhonov#include "lsquic_spi.h" 2850aadb33SDmitri Tikhonov 2950aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_SPI 305392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(iter->spi_conn) 3150aadb33SDmitri Tikhonov#include "lsquic_logger.h" 3250aadb33SDmitri Tikhonov 33461e84d8SAmol Deshpande#define SPI_DEBUG(fmt, ...) LSQ_DEBUG("%s: " fmt, iter->spi_name, __VA_ARGS__) 3450aadb33SDmitri Tikhonov 3550aadb33SDmitri Tikhonov#define NEXT_STREAM(stream, off) \ 3650aadb33SDmitri Tikhonov (* (struct lsquic_stream **) ((unsigned char *) (stream) + (off))) 3750aadb33SDmitri Tikhonov 3850aadb33SDmitri Tikhonov 3950aadb33SDmitri Tikhonovstatic void 4050aadb33SDmitri Tikhonovadd_stream_to_spi (struct stream_prio_iter *iter, lsquic_stream_t *stream) 4150aadb33SDmitri Tikhonov{ 4250aadb33SDmitri Tikhonov unsigned set, bit; 4350aadb33SDmitri Tikhonov set = stream->sm_priority >> 6; 4450aadb33SDmitri Tikhonov bit = stream->sm_priority & 0x3F; 4550aadb33SDmitri Tikhonov if (!(iter->spi_set[set] & (1ULL << bit))) 4650aadb33SDmitri Tikhonov { 4750aadb33SDmitri Tikhonov iter->spi_set[set] |= 1ULL << bit; 4850aadb33SDmitri Tikhonov TAILQ_INIT(&iter->spi_streams[ stream->sm_priority ]); 4950aadb33SDmitri Tikhonov } 5050aadb33SDmitri Tikhonov TAILQ_INSERT_TAIL(&iter->spi_streams[ stream->sm_priority ], 5150aadb33SDmitri Tikhonov stream, next_prio_stream); 52a0e1aeeeSDmitri Tikhonov ++iter->spi_n_added; 5350aadb33SDmitri Tikhonov} 5450aadb33SDmitri Tikhonov 5550aadb33SDmitri Tikhonov 5650aadb33SDmitri Tikhonovvoid 57fbc6cc04SDmitri Tikhonovlsquic_spi_init (void *iter_p, struct lsquic_stream *first, 585392f7a3SLiteSpeed Tech struct lsquic_stream *last, uintptr_t next_ptr_offset, 59fbc6cc04SDmitri Tikhonov struct lsquic_conn_public *conn_pub, 605392f7a3SLiteSpeed Tech const char *name, 615392f7a3SLiteSpeed Tech int (*filter)(void *filter_ctx, struct lsquic_stream *), 625392f7a3SLiteSpeed Tech void *filter_ctx) 6350aadb33SDmitri Tikhonov{ 64fbc6cc04SDmitri Tikhonov struct stream_prio_iter *const iter = iter_p; 6550aadb33SDmitri Tikhonov struct lsquic_stream *stream; 6650aadb33SDmitri Tikhonov unsigned count; 6750aadb33SDmitri Tikhonov 68fbc6cc04SDmitri Tikhonov iter->spi_conn = conn_pub->lconn; 6950aadb33SDmitri Tikhonov iter->spi_name = name ? name : "UNSET"; 7050aadb33SDmitri Tikhonov iter->spi_set[0] = 0; 7150aadb33SDmitri Tikhonov iter->spi_set[1] = 0; 7250aadb33SDmitri Tikhonov iter->spi_set[2] = 0; 7350aadb33SDmitri Tikhonov iter->spi_set[3] = 0; 7450aadb33SDmitri Tikhonov iter->spi_cur_prio = 0; 7550aadb33SDmitri Tikhonov iter->spi_next_stream = NULL; 76a0e1aeeeSDmitri Tikhonov iter->spi_n_added = 0; 7750aadb33SDmitri Tikhonov 7850aadb33SDmitri Tikhonov stream = first; 7950aadb33SDmitri Tikhonov count = 0; 8050aadb33SDmitri Tikhonov 8119f667fbSDmitri Tikhonov if (filter) 8219f667fbSDmitri Tikhonov while (1) 8319f667fbSDmitri Tikhonov { 8419f667fbSDmitri Tikhonov if (filter(filter_ctx, stream)) 8519f667fbSDmitri Tikhonov { 8619f667fbSDmitri Tikhonov add_stream_to_spi(iter, stream); 8719f667fbSDmitri Tikhonov ++count; 8819f667fbSDmitri Tikhonov } 8919f667fbSDmitri Tikhonov if (stream == last) 9019f667fbSDmitri Tikhonov break; 9119f667fbSDmitri Tikhonov stream = NEXT_STREAM(stream, next_ptr_offset); 9219f667fbSDmitri Tikhonov } 9319f667fbSDmitri Tikhonov else 9419f667fbSDmitri Tikhonov while (1) 9519f667fbSDmitri Tikhonov { 9619f667fbSDmitri Tikhonov add_stream_to_spi(iter, stream); 9719f667fbSDmitri Tikhonov ++count; 9819f667fbSDmitri Tikhonov if (stream == last) 9919f667fbSDmitri Tikhonov break; 10019f667fbSDmitri Tikhonov stream = NEXT_STREAM(stream, next_ptr_offset); 10119f667fbSDmitri Tikhonov } 102c51ce338SDmitri Tikhonov 10350aadb33SDmitri Tikhonov if (count > 2) 10450aadb33SDmitri Tikhonov SPI_DEBUG("initialized; # elems: %u; sets: [ %016"PRIX64", %016"PRIX64 10550aadb33SDmitri Tikhonov ", %016"PRIX64", %016"PRIX64" ]", count, iter->spi_set[0], 10650aadb33SDmitri Tikhonov iter->spi_set[1], iter->spi_set[2], iter->spi_set[3]); 10750aadb33SDmitri Tikhonov} 10850aadb33SDmitri Tikhonov 10950aadb33SDmitri Tikhonov 11050aadb33SDmitri Tikhonovstatic int 11150aadb33SDmitri Tikhonovfind_and_set_lowest_priority (struct stream_prio_iter *iter) 11250aadb33SDmitri Tikhonov{ 11350aadb33SDmitri Tikhonov unsigned set, prio; 11450aadb33SDmitri Tikhonov uint64_t mask; 11550aadb33SDmitri Tikhonov 11650aadb33SDmitri Tikhonov for (set = 0, prio = 0; set < 4; ++set, prio += 64) 11750aadb33SDmitri Tikhonov if (iter->spi_set[ set ]) 11850aadb33SDmitri Tikhonov break; 11950aadb33SDmitri Tikhonov 1208ca33e0eSDmitri Tikhonov if (set >= 4) 12150aadb33SDmitri Tikhonov { 12250aadb33SDmitri Tikhonov //SPI_DEBUG("%s: cannot find any", __func__); 12350aadb33SDmitri Tikhonov return -1; 12450aadb33SDmitri Tikhonov } 12550aadb33SDmitri Tikhonov 12650aadb33SDmitri Tikhonov mask = iter->spi_set[set]; 12750aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 32) - 1))) { prio += 32; mask >>= 32; } 12850aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 16) - 1))) { prio += 16; mask >>= 16; } 12950aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 8) - 1))) { prio += 8; mask >>= 8; } 13050aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 4) - 1))) { prio += 4; mask >>= 4; } 13150aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 2) - 1))) { prio += 2; mask >>= 2; } 13250aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 1) - 1))) { prio += 1; } 13350aadb33SDmitri Tikhonov 13450aadb33SDmitri Tikhonov#ifndef NDEBUG 13550aadb33SDmitri Tikhonov unsigned bit; 13650aadb33SDmitri Tikhonov set = prio >> 6; 13750aadb33SDmitri Tikhonov bit = prio & 0x3F; 13850aadb33SDmitri Tikhonov assert(iter->spi_set[ set ] & (1ULL << bit)); 13950aadb33SDmitri Tikhonov#endif 14050aadb33SDmitri Tikhonov 14150aadb33SDmitri Tikhonov SPI_DEBUG("%s: prio %u -> %u", __func__, iter->spi_cur_prio, prio); 1422d296031SDmitri Tikhonov iter->spi_cur_prio = (unsigned char) prio; 14350aadb33SDmitri Tikhonov return 0; 14450aadb33SDmitri Tikhonov} 14550aadb33SDmitri Tikhonov 14650aadb33SDmitri Tikhonov 14750aadb33SDmitri Tikhonovstatic int 14850aadb33SDmitri Tikhonovfind_and_set_next_priority (struct stream_prio_iter *iter) 14950aadb33SDmitri Tikhonov{ 15050aadb33SDmitri Tikhonov unsigned set, bit, prio; 15150aadb33SDmitri Tikhonov uint64_t mask; 15250aadb33SDmitri Tikhonov 15350aadb33SDmitri Tikhonov /* Examine values in the same set first */ 15450aadb33SDmitri Tikhonov set = iter->spi_cur_prio >> 6; 15550aadb33SDmitri Tikhonov bit = iter->spi_cur_prio & 0x3F; 15650aadb33SDmitri Tikhonov prio = 64 * set; 15750aadb33SDmitri Tikhonov 15850aadb33SDmitri Tikhonov if (bit < 63) 15950aadb33SDmitri Tikhonov { 16050aadb33SDmitri Tikhonov mask = iter->spi_set[set]; 16150aadb33SDmitri Tikhonov mask &= ~((1ULL << (bit + 1)) - 1); 16250aadb33SDmitri Tikhonov if (mask) 16350aadb33SDmitri Tikhonov goto calc_priority; 16450aadb33SDmitri Tikhonov } 16550aadb33SDmitri Tikhonov 16650aadb33SDmitri Tikhonov ++set; 16750aadb33SDmitri Tikhonov prio += 64; 16850aadb33SDmitri Tikhonov for (; set < 4; ++set, prio += 64) 16950aadb33SDmitri Tikhonov if (iter->spi_set[ set ]) 17050aadb33SDmitri Tikhonov break; 17150aadb33SDmitri Tikhonov 17203fb9352SDmitri Tikhonov if (set >= 4) 17350aadb33SDmitri Tikhonov { 17450aadb33SDmitri Tikhonov //SPI_DEBUG("%s: cannot find any", __func__); 17550aadb33SDmitri Tikhonov return -1; 17650aadb33SDmitri Tikhonov } 17750aadb33SDmitri Tikhonov 17850aadb33SDmitri Tikhonov mask = iter->spi_set[set]; 17950aadb33SDmitri Tikhonov 18050aadb33SDmitri Tikhonov calc_priority: 18150aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 32) - 1))) { prio += 32; mask >>= 32; } 18250aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 16) - 1))) { prio += 16; mask >>= 16; } 18350aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 8) - 1))) { prio += 8; mask >>= 8; } 18450aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 4) - 1))) { prio += 4; mask >>= 4; } 18550aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 2) - 1))) { prio += 2; mask >>= 2; } 18650aadb33SDmitri Tikhonov if (!(mask & ((1ULL << 1) - 1))) { prio += 1; } 18750aadb33SDmitri Tikhonov 18850aadb33SDmitri Tikhonov#ifndef NDEBUG 18950aadb33SDmitri Tikhonov set = prio >> 6; 19050aadb33SDmitri Tikhonov bit = prio & 0x3F; 19150aadb33SDmitri Tikhonov assert(iter->spi_set[ set ] & (1ULL << bit)); 19250aadb33SDmitri Tikhonov#endif 19350aadb33SDmitri Tikhonov 19450aadb33SDmitri Tikhonov SPI_DEBUG("%s: prio %u -> %u", __func__, iter->spi_cur_prio, prio); 1952d296031SDmitri Tikhonov iter->spi_cur_prio = (unsigned char) prio; 19650aadb33SDmitri Tikhonov return 0; 19750aadb33SDmitri Tikhonov} 19850aadb33SDmitri Tikhonov 19950aadb33SDmitri Tikhonov 20050aadb33SDmitri Tikhonovlsquic_stream_t * 201fbc6cc04SDmitri Tikhonovlsquic_spi_first (void *iter_p) 20250aadb33SDmitri Tikhonov{ 203fbc6cc04SDmitri Tikhonov struct stream_prio_iter *const iter = iter_p; 20450aadb33SDmitri Tikhonov lsquic_stream_t *stream; 20550aadb33SDmitri Tikhonov unsigned set, bit; 20650aadb33SDmitri Tikhonov 20750aadb33SDmitri Tikhonov iter->spi_cur_prio = 0; 20850aadb33SDmitri Tikhonov set = iter->spi_cur_prio >> 6; 20950aadb33SDmitri Tikhonov bit = iter->spi_cur_prio & 0x3F; 21050aadb33SDmitri Tikhonov 21150aadb33SDmitri Tikhonov if (!(iter->spi_set[set] & (1ULL << bit))) 21250aadb33SDmitri Tikhonov { 21350aadb33SDmitri Tikhonov if (0 != find_and_set_lowest_priority(iter)) 21450aadb33SDmitri Tikhonov { 21550aadb33SDmitri Tikhonov SPI_DEBUG("%s: return NULL", __func__); 21650aadb33SDmitri Tikhonov return NULL; 21750aadb33SDmitri Tikhonov } 21850aadb33SDmitri Tikhonov } 21950aadb33SDmitri Tikhonov 22050aadb33SDmitri Tikhonov stream = TAILQ_FIRST(&iter->spi_streams[ iter->spi_cur_prio ]); 22150aadb33SDmitri Tikhonov iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream); 2225392f7a3SLiteSpeed Tech if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) && !lsquic_stream_is_critical(stream)) 2235392f7a3SLiteSpeed Tech SPI_DEBUG("%s: return stream %"PRIu64", priority %u", __func__, 2245392f7a3SLiteSpeed Tech stream->id, iter->spi_cur_prio); 22550aadb33SDmitri Tikhonov return stream; 22650aadb33SDmitri Tikhonov} 22750aadb33SDmitri Tikhonov 22850aadb33SDmitri Tikhonov 22950aadb33SDmitri Tikhonovlsquic_stream_t * 230fbc6cc04SDmitri Tikhonovlsquic_spi_next (void *iter_p) 23150aadb33SDmitri Tikhonov{ 232fbc6cc04SDmitri Tikhonov struct stream_prio_iter *const iter = iter_p; 23350aadb33SDmitri Tikhonov lsquic_stream_t *stream; 23450aadb33SDmitri Tikhonov 23550aadb33SDmitri Tikhonov stream = iter->spi_next_stream; 23650aadb33SDmitri Tikhonov if (stream) 23750aadb33SDmitri Tikhonov { 23850aadb33SDmitri Tikhonov iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream); 2395392f7a3SLiteSpeed Tech if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) && !lsquic_stream_is_critical(stream)) 2405392f7a3SLiteSpeed Tech SPI_DEBUG("%s: return stream %"PRIu64", priority %u", __func__, 2415392f7a3SLiteSpeed Tech stream->id, iter->spi_cur_prio); 24250aadb33SDmitri Tikhonov return stream; 24350aadb33SDmitri Tikhonov } 24450aadb33SDmitri Tikhonov 24550aadb33SDmitri Tikhonov if (0 != find_and_set_next_priority(iter)) 24650aadb33SDmitri Tikhonov { 24750aadb33SDmitri Tikhonov //SPI_DEBUG("%s: return NULL", __func__); 24850aadb33SDmitri Tikhonov return NULL; 24950aadb33SDmitri Tikhonov } 25050aadb33SDmitri Tikhonov 25150aadb33SDmitri Tikhonov stream = TAILQ_FIRST(&iter->spi_streams[ iter->spi_cur_prio ]); 25250aadb33SDmitri Tikhonov iter->spi_next_stream = TAILQ_NEXT(stream, next_prio_stream); 25350aadb33SDmitri Tikhonov 2545392f7a3SLiteSpeed Tech if (LSQ_LOG_ENABLED(LSQ_LOG_DEBUG) && !lsquic_stream_is_critical(stream)) 2555392f7a3SLiteSpeed Tech SPI_DEBUG("%s: return stream %"PRIu64", priority %u", __func__, 2565392f7a3SLiteSpeed Tech stream->id, iter->spi_cur_prio); 25750aadb33SDmitri Tikhonov return stream; 25850aadb33SDmitri Tikhonov} 25950aadb33SDmitri Tikhonov 26050aadb33SDmitri Tikhonov 261c51ce338SDmitri Tikhonovstatic int 262c51ce338SDmitri Tikhonovhave_non_critical_streams (const struct stream_prio_iter *iter) 263c51ce338SDmitri Tikhonov{ 264c51ce338SDmitri Tikhonov const struct lsquic_stream *stream; 265c51ce338SDmitri Tikhonov TAILQ_FOREACH(stream, &iter->spi_streams[ iter->spi_cur_prio ], 266c51ce338SDmitri Tikhonov next_prio_stream) 267c51ce338SDmitri Tikhonov if (!lsquic_stream_is_critical(stream)) 268c51ce338SDmitri Tikhonov return 1; 269c51ce338SDmitri Tikhonov return 0; 270c51ce338SDmitri Tikhonov} 271c51ce338SDmitri Tikhonov 272c51ce338SDmitri Tikhonov 273a0e1aeeeSDmitri Tikhonov#if __GNUC__ 274a0e1aeeeSDmitri Tikhonov# define popcount __builtin_popcountll 275a0e1aeeeSDmitri Tikhonov#else 276a0e1aeeeSDmitri Tikhonovstatic int 277a0e1aeeeSDmitri Tikhonovpopcount (unsigned long long v) 278a0e1aeeeSDmitri Tikhonov{ 279a0e1aeeeSDmitri Tikhonov int count, i; 280a0e1aeeeSDmitri Tikhonov for (i = 0, count = 0; i < sizeof(v) * 8; ++i) 281a0e1aeeeSDmitri Tikhonov if (v & (1 << i)) 282a0e1aeeeSDmitri Tikhonov ++count; 283a0e1aeeeSDmitri Tikhonov return count; 284a0e1aeeeSDmitri Tikhonov} 285a0e1aeeeSDmitri Tikhonov 286a0e1aeeeSDmitri Tikhonov 287a0e1aeeeSDmitri Tikhonov#endif 288a0e1aeeeSDmitri Tikhonov 289a0e1aeeeSDmitri Tikhonov 290a0e1aeeeSDmitri Tikhonovstatic int 291a0e1aeeeSDmitri Tikhonovspi_has_more_than_one_queue (const struct stream_prio_iter *iter) 292a0e1aeeeSDmitri Tikhonov{ 293a0e1aeeeSDmitri Tikhonov unsigned i; 294a0e1aeeeSDmitri Tikhonov int count; 295a0e1aeeeSDmitri Tikhonov 296a0e1aeeeSDmitri Tikhonov if (iter->spi_n_added < 2) 297a0e1aeeeSDmitri Tikhonov return 0; 298a0e1aeeeSDmitri Tikhonov 299a0e1aeeeSDmitri Tikhonov count = 0; 300a0e1aeeeSDmitri Tikhonov for (i = 0; i < sizeof(iter->spi_set) / sizeof(iter->spi_set[0]); ++i) 301a0e1aeeeSDmitri Tikhonov { 302a0e1aeeeSDmitri Tikhonov count += popcount(iter->spi_set[i]); 303a0e1aeeeSDmitri Tikhonov if (count > 1) 304a0e1aeeeSDmitri Tikhonov return 1; 305a0e1aeeeSDmitri Tikhonov } 306a0e1aeeeSDmitri Tikhonov 307a0e1aeeeSDmitri Tikhonov return 0; 308a0e1aeeeSDmitri Tikhonov} 309a0e1aeeeSDmitri Tikhonov 310a0e1aeeeSDmitri Tikhonov 311c51ce338SDmitri Tikhonovstatic void 312fbc6cc04SDmitri Tikhonovspi_drop_high_or_non_high (void *iter_p, int drop_high) 313c51ce338SDmitri Tikhonov{ 314fbc6cc04SDmitri Tikhonov struct stream_prio_iter *const iter = iter_p; 315c51ce338SDmitri Tikhonov uint64_t new_set[ sizeof(iter->spi_set) / sizeof(iter->spi_set[0]) ]; 316c51ce338SDmitri Tikhonov unsigned bit, set, n; 317c51ce338SDmitri Tikhonov 318a0e1aeeeSDmitri Tikhonov if (!spi_has_more_than_one_queue(iter)) 319a0e1aeeeSDmitri Tikhonov return; 320a0e1aeeeSDmitri Tikhonov 321c51ce338SDmitri Tikhonov memset(new_set, 0, sizeof(new_set)); 322c51ce338SDmitri Tikhonov 323c51ce338SDmitri Tikhonov find_and_set_lowest_priority(iter); 324c51ce338SDmitri Tikhonov set = iter->spi_cur_prio >> 6; 325c51ce338SDmitri Tikhonov bit = iter->spi_cur_prio & 0x3F; 326c51ce338SDmitri Tikhonov new_set[set] |= 1ULL << bit; 327c51ce338SDmitri Tikhonov 328c51ce338SDmitri Tikhonov if (!have_non_critical_streams(iter)) 329c51ce338SDmitri Tikhonov { 330c51ce338SDmitri Tikhonov ++iter->spi_cur_prio; 331c51ce338SDmitri Tikhonov find_and_set_lowest_priority(iter); 332c51ce338SDmitri Tikhonov set = iter->spi_cur_prio >> 6; 333c51ce338SDmitri Tikhonov bit = iter->spi_cur_prio & 0x3F; 334c51ce338SDmitri Tikhonov new_set[set] |= 1ULL << bit; 335c51ce338SDmitri Tikhonov } 336c51ce338SDmitri Tikhonov 337c51ce338SDmitri Tikhonov for (n = 0; n < sizeof(new_set) / sizeof(new_set[0]); ++n) 338c51ce338SDmitri Tikhonov if (drop_high) 339c51ce338SDmitri Tikhonov iter->spi_set[n] &= ~new_set[n]; 340c51ce338SDmitri Tikhonov else 341c51ce338SDmitri Tikhonov iter->spi_set[n] = new_set[n]; 342c51ce338SDmitri Tikhonov} 343c51ce338SDmitri Tikhonov 344c51ce338SDmitri Tikhonov 345c51ce338SDmitri Tikhonovvoid 346fbc6cc04SDmitri Tikhonovlsquic_spi_drop_high (void *iter_p) 347c51ce338SDmitri Tikhonov{ 348fbc6cc04SDmitri Tikhonov struct stream_prio_iter *const iter = iter_p; 349c51ce338SDmitri Tikhonov spi_drop_high_or_non_high(iter, 1); 350c51ce338SDmitri Tikhonov} 351c51ce338SDmitri Tikhonov 352c51ce338SDmitri Tikhonov 35350aadb33SDmitri Tikhonovvoid 354fbc6cc04SDmitri Tikhonovlsquic_spi_drop_non_high (void *iter_p) 35550aadb33SDmitri Tikhonov{ 356fbc6cc04SDmitri Tikhonov struct stream_prio_iter *const iter = iter_p; 357c51ce338SDmitri Tikhonov spi_drop_high_or_non_high(iter, 0); 35850aadb33SDmitri Tikhonov} 359fbc6cc04SDmitri Tikhonov 360fbc6cc04SDmitri Tikhonov 361fbc6cc04SDmitri Tikhonovvoid 362fbc6cc04SDmitri Tikhonovlsquic_spi_cleanup (void *iter_p) 363fbc6cc04SDmitri Tikhonov{ 364fbc6cc04SDmitri Tikhonov} 365