📄 channels.c
字号:
/* -*-C-*- * * $Revision: 1.13.2.11 $ * $Author: rivimey $ * $Date: 1998/03/11 10:38:37 $ * * Copyright (c) 1996 Advanced RISC Machines Limited. * All Rights Reserved. * * Project: ANGEL * * Title: Implementation of channels layer */#include <stdlib.h> /* for NULL macro */#include "channels.h"#include "chandefs.h"#include "chanpriv.h"#include "devclnt.h"#include "devconf.h"#include "logging.h"#include "serlock.h"#include "adp.h"#include "adperr.h"#include "endian.h"#include "msgbuild.h"/* General purpose constants, macros, enums, typedefs *//* * The number of packets which can be outstanding at once -- normally * called the window size. In this case, though, the window size is * in a sense 1 as each channel is stop-and-wait. However, theoretically * all channels could have sent a packet and none received an ack, so * the number of outstanding packets possible is the number of configured * channels. */#define MAX_UNACKED CI_NUM_CHANNELS/********************************************************************** * T Y P E D E F I N I T I O N S **********************************************************************/enum ChanPrivateErrors{ CE_BLOCKING = CE_PRIVATE, /* used for blocking reads and sends */ CE_UNBLOCK_BASE, CE_UNBLOCK_OKAY = CE_UNBLOCK_BASE + CE_OKAY};/* state per channel */struct ChanState{ ChanRx_CB_Fn reader; /* the read callback, or NULL */ void *read_cb_data; /* the read callback data */ p_Buffer read_buffer; /* for blocking reads */ unsigned int read_len; /* for blocking reads */ bool read_blocking; /* for blocking reads */ ChanTx_CB_Fn writer; /* the write callback, or NULL */ void *write_cb_data; /* the write callback data */ bool write_blocking; /* for blocking sends */ p_Buffer write_buff; /* buffer being written */};/* state per device *//* * ackExpected and currentFrame form the lower and upper edges of the sender's * window. * * frameExpected is the lower and upper edges of the receiver's * window. */struct DevState{ SequenceNR currentFrame; /* seq number of last frame sent */ SequenceNR ackExpected; /* seq number of successfully-received frame */ SequenceNR frameExpected; /* seq number of last received frame from host */ SequenceNR lastReceived; /* distinguish heartbeat(8) from data(8) */ /* * The following is used to implement a list of buffers which have yet to * be acknowledged. */ struct _unacked { p_Buffer buf; /* the list of un-acked packets */ unsigned short len; /* the length of data in this packet */ int packno; /* packet sequence number for this packet */ short next; /* next buffer in this list, LISTEND => none */ } unackedBufs[MAX_UNACKED]; short firstFree; /* first free buffer, LISTEND => none */ short lastUsed; /* last (most recently pushed) buffer, LISTEND => none */ short firstUsed; /* first (oldest) buffer, LISTEND => none */};#define LISTEND (-1)extern int booted_flow_controlled;/********************************************************************** * M O D U L E D A T A **********************************************************************//* Publically-accessible globals *//* do we acknowledge heartbeats; TRUE by default. */unsigned Angel_AckedHeartbeats = 1;/* the default size of a channel buffer, for global use */unsigned Angel_ChanBuffSize = 0;/* the size of a long buffer, for global use */unsigned Angel_ChanLongSize = 0;/* Private globals *//* the state of each channel */static volatile struct ChanState chan_state[CI_NUM_CHANNELS];/* the state of each device */static struct DevState dev_state[DI_NUM_DEVICES];/* the active device */static DeviceID active_device = DE_DEFAULT_ACTIVE;/* the reader-of-all-devices */static ChannelID read_all_channel;static ChanRx_CB_Fn read_all_callback = NULL;static void *read_all_cb_data = NULL;/********************************************************************** * P R O T O T Y P E D E C L A R A T I O N S **********************************************************************//* forward declarations */static p_Buffer angel_ChannelAllocDevBuffer(unsigned req_size, void *cb_data);static AdpErrs resend_packet_from(DeviceID devid, SequenceNR packet_no);static void angel_ChannelQuerySizes(unsigned *default_size, unsigned *max_size);/********************************************************************** * I N T E R N A L F U N C T I O N S **********************************************************************//* * Function: adp_between * Purpose: To return TRUE if a <= b < c circularly. * * Params: * Input: none * * Returns: TRUE/FALSE */static intadp_between(SequenceNR a, SequenceNR b, SequenceNR c){ return (((a <= b) && (b < c)) || ((c < a) && (a <= b)) || ((b < c) && (c < a)));}/* * Function: angel_InitResendList * Purpose: To initialise the resend list - link all elements onto * the free list, and setting the used list to empty * * Params: * Input: dev - the device to initialise. * * Returns: none */static voidangel_InitResendList(register struct DevState *dev){ register int i; dev->firstFree = 0; dev->firstUsed = LISTEND; dev->lastUsed = LISTEND; for(i = 0; i < MAX_UNACKED; i++) { dev->unackedBufs[i].buf = NULL; dev->unackedBufs[i].len = 0; dev->unackedBufs[i].packno = 0; dev->unackedBufs[i].next = i + 1; } dev->unackedBufs[i - 1].next = LISTEND; return;}/* * Function: Angel_InitChannels * Purpose: To Initialise the sequence numbers, and resend list. * This should be called only when the state of memory * is unknown (i.e. the data structures are random). * * Params: * Input: none * * Returns: adp_ok */AdpErrsAngel_InitChannels(void){ int j; LogInfo(LOG_CHANNEL, ( "Angel_InitChannels: resetting...\n")); Angel_EnterCriticalSection(); for (j = 0; j < DI_NUM_DEVICES; j++) { register struct DevState *dev = &dev_state[j]; dev->currentFrame = 0; dev->ackExpected = 0; dev->lastReceived = 0; dev->frameExpected = 1; angel_InitResendList(dev); } Angel_LeaveCriticalSection(); LogInfo(LOG_CHANNEL, ( "Angel_InitChannels: reset channels.\n")); return adp_ok;}/* * Function: Angel_ReinitChannels * Purpose: To re initialise the device; very similar to the * initialise, but assumes the device state is "sensible", * freeing any buffers allocated on the resend list. * * Params: * Input: none * * Returns: adp_ok */AdpErrsAngel_ReinitChannels(void){ int i, j; LogInfo(LOG_CHANNEL, ( "Angel_ReinitChannels: resetting...\n")); Angel_EnterCriticalSection(); for (j = 0; j < DI_NUM_DEVICES; j++) { register struct DevState *dev = &dev_state[j]; dev->currentFrame = 0; dev->ackExpected = 0; dev->lastReceived = 0; dev->frameExpected = 1; /* free all packets on the used list */ i = dev->firstUsed; while ( i != LISTEND ) { if (dev->unackedBufs[i].buf) { Angel_BufferRelease(dev->unackedBufs[i].buf); } i = dev->unackedBufs[i].next; } /* then reinitialise the free list. */ angel_InitResendList(dev); } Angel_LeaveCriticalSection(); LogInfo(LOG_CHANNEL, ( "Angel_ReinitChannels: reset channels.\n")); return adp_ok;}/* * Function: adp_get_unack_bufno * Purpose: To search the resend list for a given packet and return the buffer * number in which it is located. Additionally, return the previous * buffer number, if any, for the purposes of list pointer changes. * * Params: * Input: devid - the device ID of the driver * pkt_no - the packet number required * startbuf - the initial buffer index (use to select btw. free * and used buffer lists) * * Output: prev - if non-null, a pointer to a value holding the previous * buffer, whose next pointer points at the wanted one, or * LISTEND signifying this was the first buffer. * * Returns: OK: the buffer index of the required buffer * Error: LISTEND if packet number not found */static int adp_get_unack_bufno(DeviceID devid, SequenceNR pkt_no, short startbuf, short *prev){ register struct DevState *dev = &dev_state[devid]; register short i, j = LISTEND; for (i = startbuf; i != LISTEND; i = dev->unackedBufs[i].next) { if (dev->unackedBufs[i].packno == pkt_no) { if (prev != NULL) *prev = j; return i; } j = i; } return LISTEND;}/* * Function: Angel_show_unacked_list * Purpose: To display the used and free resend lists for a given device. * * Params: * Input: devid - the device ID of the driver * * Returns: none */#if DEBUG == 1static void Angel_show_unacked_list(DeviceID devid){ register struct DevState *dev = &dev_state[devid]; register int i; LogInfo(LOG_CHANNEL, ("Resend list for Device %d\n", devid)); for (i = dev->firstUsed; i != LISTEND; i = dev->unackedBufs[i].next) { LogInfo(LOG_CHANNEL, (" Buffer %d: Packet %d unacked (@%x, len %d)\n", i, dev->unackedBufs[i].packno, dev->unackedBufs[i].buf, dev->unackedBufs[i].len)); }}#else#define Angel_show_unacked_list(d)#endif/* * Function: adp_add_pkt * Purpose: To add the given packet to the resend list. * * Params: * Input: devid - the device ID of the driver * pkt_no - the packet number required * buffer - the buffer pointer for this packet * len - the length of this packet in bytes * * Returns: adp_ok */static AdpErrs adp_add_pkt(DeviceID devid, SequenceNR pkt_no, p_Buffer buffer, int len){ int b; /* the list reference number of the packet to add */ register struct DevState *dev = &dev_state[devid]; Angel_EnterCriticalSection(); if (dev->firstFree != LISTEND) { /* remove this buffer from the free list */ b = dev->firstFree; dev->firstFree = dev->unackedBufs[b].next; /* set it up... */ dev->unackedBufs[b].buf = buffer; dev->unackedBufs[b].len = len; dev->unackedBufs[b].packno = pkt_no; /* now add it onto the unacked buffer list. firstUsed is the head -- set * this if the list was initially empty. lastUsed is the tail; set this * to the current buffer after modifying the old 'next' pointer. */ dev->unackedBufs[b].next = LISTEND; if (dev->lastUsed != LISTEND) dev->unackedBufs[dev->lastUsed].next = b; else dev->firstUsed = b;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -