timeout.c 4.3 KB
Newer Older
1
/*
2 3 4 5
 * Copyright (C) 2013 CERN (www.cern.ch)
 * Author: Alessandro Rubini
 *
 * Released according to the GNU LGPL, version 2.1 or any later version.
6 7 8
 */
#include <ppsi/ppsi.h>

9 10 11 12 13 14
enum rand_type {
	RAND_NONE,	/* Not randomized */
	RAND_70_130,	/* Should be 70% to 130% of 1 << value */
	RAND_0_200,	/* Should be 0% to 200% of 1 << value */
};

15 16
struct timeout_config {
	char *name;
17
	int which_rand;
18
	int value;
19 20
};

21 22
/* most timeouts have a static configuration. Save it here */
static struct timeout_config to_configs[__PP_TO_ARRAY_SIZE] = {
23 24 25 26 27
	[PP_TO_REQUEST] =	{"REQUEST",	RAND_0_200,},
	[PP_TO_SYNC_SEND] =	{"SYNC_SEND",	RAND_70_130,},
	[PP_TO_ANN_RECEIPT] =	{"ANN_RECEIPT",	RAND_NONE,},
	[PP_TO_ANN_SEND] =	{"ANN_SEND",	RAND_70_130,},
	[PP_TO_FAULTY] =	{"FAULTY",	RAND_NONE, 4000},
28
	[PP_TO_QUALIFICATION] = {"QUAL",	RAND_NONE,}
29 30 31
	/* extension timeouts are explicitly set to a value */
};

32
/* Init fills the timeout values */
33 34 35 36 37 38 39 40 41 42 43
void pp_timeout_init(struct pp_instance *ppi)
{
	struct DSPort *port = ppi->portDS;

	to_configs[PP_TO_REQUEST].value =
		port->logMinDelayReqInterval;
	to_configs[PP_TO_SYNC_SEND].value =
		port->logSyncInterval;
	to_configs[PP_TO_ANN_RECEIPT].value = 1000 * (
		port->announceReceiptTimeout << port->logAnnounceInterval);
	to_configs[PP_TO_ANN_SEND].value = port->logAnnounceInterval;
44 45
	to_configs[PP_TO_QUALIFICATION].value =
	    (1000 << port->logAnnounceInterval)*(DSCUR(ppi)->stepsRemoved + 1);
46 47 48 49 50
}

void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec)
{
	ppi->timeouts[index] = ppi->t_ops->calc_timeout(ppi, millisec);
51 52
	pp_diag(ppi, time, 3, "new timeout for %s: %i\n",
		to_configs[index].name, millisec);
53 54
}

55

56
void pp_timeout_set(struct pp_instance *ppi, int index)
57 58 59 60
{
	static uint32_t seed;
	uint32_t rval;
	int millisec;
61 62
	int logval = to_configs[index].value;

63 64 65
	if (!seed) {
		uint32_t *p;
		/* use the least 32 bits of the mac address as seed */
66
		p = (void *)(&DSDEF(ppi)->clockIdentity)
67 68 69 70 71 72 73 74 75 76 77 78 79
			+ sizeof(ClockIdentity) - 4;
		seed = *p;
	}
	/* From uclibc: they make 11 + 10 + 10 bits, we stop at 21 */
	seed *= 1103515245;
	seed += 12345;
	rval = (unsigned int) (seed / 65536) % 2048;

	seed *= 1103515245;
	seed += 12345;
	rval <<= 10;
	rval ^= (unsigned int) (seed / 65536) % 1024;

80 81 82 83 84
	/*
	 * logval is signed. Let's imagine it's no less than -4.
	 * Here below, 0 gets to 16 * 25 = 400ms, 40% of the nominal value
	 */
	millisec = (1 << (logval + 4)) * 25;
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	switch(to_configs[index].which_rand) {
	case RAND_70_130:
		/*
		 * We are required to fit between 70% and 130%
		 * of the value for 90% of the time, at least.
		 * So randomize between 80% and 120%: constant
		 * part is 80% and variable is 40%.
		 */
		millisec = (millisec * 2) + rval % millisec;
		break;
	case RAND_0_200:
		millisec = rval % (millisec * 5);
		break;
	case RAND_NONE:
		millisec = logval; /* not a log, just a constant */
	}
102
	__pp_timeout_set(ppi, index, millisec);
103 104
}

105 106 107 108 109 110 111 112 113 114 115 116 117
/*
 * When we enter a new fsm state, we init all timeouts. Who cares if
 * some of them are not used (and even if some have no default timeout)
 */
void pp_timeout_setall(struct pp_instance *ppi)
{
	int i;
	for (i = 0; i < __PP_TO_ARRAY_SIZE; i++)
		pp_timeout_set(ppi, i);
	/* but announce_send must be send soon */
	__pp_timeout_set(ppi, PP_TO_ANN_SEND, 20);
}

118 119
int pp_timeout(struct pp_instance *ppi, int index)
{
120 121
	int ret = time_after_eq(ppi->t_ops->calc_timeout(ppi, 0),
				ppi->timeouts[index]);
122 123

	if (ret)
124 125
		pp_diag(ppi, time, 1, "timeout expired: %s\n",
			to_configs[index].name);
126 127 128
	return ret;
}

129 130 131 132 133
/*
 * How many ms to wait for the timeout to happen, for ppi->next_delay.
 * It is not allowed for a timeout to not be pending
 */
int pp_next_delay_1(struct pp_instance *ppi, int i1)
134
{
135 136
	unsigned long now = ppi->t_ops->calc_timeout(ppi, 0);
	signed long r1;
137

138 139
	r1 = ppi->timeouts[i1] - now;
	return r1 < 0 ? 0 : r1;
140 141
}

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
int pp_next_delay_2(struct pp_instance *ppi, int i1, int i2)
{
	unsigned long now = ppi->t_ops->calc_timeout(ppi, 0);
	signed long r1, r2;

	r1 = ppi->timeouts[i1] - now;
	r2 = ppi->timeouts[i2] - now;
	if (r2 < r1)
		r1 = r2;
	return r1 < 0 ? 0 : r1;
}

int pp_next_delay_3(struct pp_instance *ppi, int i1, int i2, int i3)
{
	unsigned long now = ppi->t_ops->calc_timeout(ppi, 0);
	signed long r1, r2, r3;

	r1 = ppi->timeouts[i1] - now;
	r2 = ppi->timeouts[i2] - now;
	r3 = ppi->timeouts[i3] - now;
	if (r2 < r1)
		r1 = r2;
	if (r3 < r1)
		r1 = r3;
	return r1 < 0 ? 0 : r1;
}