main-loop.c 3.01 KB
Newer Older
1
/*
2 3 4 5
 * Copyright (C) 2011 CERN (www.cern.ch)
 * Author: Alessandro Rubini
 *
 * Released to the public domain
6 7 8
 */

/*
9
 * This is the main loop for unix stuff.
10 11 12 13 14 15
 */
#include <stdlib.h>
#include <errno.h>
#include <sys/select.h>
#include <linux/if_ether.h>

Alessandro Rubini's avatar
Alessandro Rubini committed
16
#include <ppsi/ppsi.h>
17
#include <common-fun.h>
18
#include "ppsi-unix.h"
19

20 21 22 23 24 25 26 27
/* Call pp_state_machine for each instance. To be called periodically,
 * when no packets are incoming */
static int run_all_state_machines(struct pp_globals *ppg)
{
	int j;
	int delay_ms = 0, delay_ms_j;

	for (j = 0; j < ppg->nlinks; j++) {
28
		struct pp_instance *ppi = INST(ppg, j);
29 30 31
		delay_ms_j = pp_state_machine(ppi, NULL, 0);

		/* delay_ms is the least delay_ms among all instances */
32
		if (j == 0)
33
			delay_ms = delay_ms_j;
34 35
		if (delay_ms_j < delay_ms)
			delay_ms = delay_ms_j;
36 37 38 39 40
	}

	return delay_ms;
}

41
void unix_main_loop(struct pp_globals *ppg)
42
{
43
	struct pp_instance *ppi;
44 45 46 47 48 49
	int delay_ms;
	int j;

	/* Initialize each link's state machine */
	for (j = 0; j < ppg->nlinks; j++) {

50
		ppi = INST(ppg, j);
51 52 53 54 55

		/*
		* If we are sending or receiving raw ethernet frames,
		* the ptp payload is one-eth-header bytes into the frame
		*/
56
		if (ppi->proto == PPSI_PROTO_RAW)
57 58 59 60 61 62 63
			NP(ppi)->ptp_offset = ETH_HLEN;

		/*
		* The main loop here is based on select. While we are not
		* doing anything else but the protocol, this allows extra stuff
		* to fit.
		*/
64
		ppi->is_new_state = 1;
65 66 67
	}

	delay_ms = run_all_state_machines(ppg);
68

69 70 71
	while (1) {
		int i;

72 73 74 75 76
		/*
		 * If Ebest was changed in previous loop, run best
		 * master clock before checking for new packets, which
		 * would affect port state again
		 */
77 78 79
		if (ppg->ebest_updated) {
			for (j = 0; j < ppg->nlinks; j++) {
				int new_state;
80
				struct pp_instance *ppi = INST(ppg, j);
81 82 83
				new_state = bmc(ppi);
				if (new_state != ppi->state) {
					ppi->state = new_state;
84
					ppi->is_new_state = 1;
85 86 87 88 89
				}
			}
			ppg->ebest_updated = 0;
		}

90
		i = unix_net_ops.check_packet(ppg, delay_ms);
91

92 93 94 95
		if (i < 0)
			continue;

		if (i == 0) {
96
			delay_ms = run_all_state_machines(ppg);
97 98 99
			continue;
		}

100
		/* If delay_ms is -1, the above ops.check_packet will continue
101 102 103 104 105 106
		 * consuming the previous timeout (see its implementation).
		 * This ensures that every state machine is called at least once
		 * every delay_ms */
		delay_ms = -1;

		for (j = 0; j < ppg->nlinks; j++) {
107
			int tmp_d;
108
			ppi = INST(ppg, j);
109

110
			if ((NP(ppi)->ch[PP_NP_GEN].pkt_present) ||
111
			    (NP(ppi)->ch[PP_NP_EVT].pkt_present)) {
112

113
				i = __recv_and_count(ppi, ppi->rx_frame,
114 115 116
						PP_MAX_FRAME_LENGTH - 4,
						&ppi->last_rcv_time);

117 118 119 120 121 122 123 124 125
				if (i == -2) {
					continue; /* dropped */
				}
				if (i == -1) {
					pp_diag(ppi, frames, 1,
						"Receive Error %i: %s\n",
						errno, strerror(errno));
					continue;
				}
126
				if (i < PP_MINIMUM_LENGTH) {
127
					pp_diag(ppi, frames, 1,
128 129
						"Short frame: %d < %d\n", i,
						PP_MINIMUM_LENGTH);
130 131 132
					continue;
				}

133
				tmp_d = pp_state_machine(ppi, ppi->rx_ptp,
134
					i - NP(ppi)->ptp_offset);
135 136 137

				if ((delay_ms == -1) || (tmp_d < delay_ms))
					delay_ms = tmp_d;
138 139
			}
		}
140 141
	}
}