aboutsummaryrefslogtreecommitdiff
path: root/daemon/Fifo.cpp
blob: bbc43a719aeb914f42268c3f3232cf81a3bd0e6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

typedef unsigned long long uint64_t;
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "Fifo.h"
#include "Logging.h"

extern void handleException();

Fifo::Fifo(int numBuffers, int bufferSize) {
	int	which;

	if (numBuffers > FIFO_BUFFER_LIMIT) {
		logg->logError(__FILE__, __LINE__, "Number of fifo buffers exceeds maximum");
		handleException();
	}
	mNumBuffers = numBuffers;
	mBufferSize = bufferSize;
	mWriteCurrent = 0;
	mReadCurrent = mNumBuffers - 1; // (n-1) pipelined

	for (which=0; which<mNumBuffers; which++) {
		// initialized read-to-write sem to 1, so that first wait goes through; write-to-read init'd to 0
		if (sem_init(&mReadToWriteSem[which], 0, 1) ||
			sem_init(&mWriteToReadSem[which], 0, 0)) {
			logg->logError(__FILE__, __LINE__, "sem_init(%d) failed", which);
			handleException();
		}
		// page-align allocate buffers
		mBuffer[which] = (char*)valloc(bufferSize);
		if (mBuffer[which] == NULL) {
			logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize);
			handleException();
		}
		// touch each page to fault it in
		for (int i=0; i<bufferSize; i+= getpagesize()) {
			*mBuffer[which] = 0;
		}
	}
}

Fifo::~Fifo() {
	for (int which=0; which<mNumBuffers; which++) {
		if (mBuffer[which] != NULL) {
			free(mBuffer[which]);
			mBuffer[which] = NULL;
		}
	}
}

int Fifo::depth(void) {
	return mNumBuffers;
}

int Fifo::numReadToWriteBuffersFilled() {
	int value;
	int numFilled = 0;
	for (int which=0; which<mNumBuffers; which++) {
		if (sem_getvalue(&mReadToWriteSem[which], &value) == 0) numFilled += value;
	}
	return numFilled;
}

int Fifo::numWriteToReadBuffersFilled() {
	int value;
	int numFilled = 0;
	for (int which=0; which<mNumBuffers; which++) {
		if (sem_getvalue(&mWriteToReadSem[which], &value) == 0) numFilled += value;
	}
	return numFilled;
}

char* Fifo::start() {
	sem_wait(&mReadToWriteSem[mWriteCurrent]);
	return mBuffer[mWriteCurrent];
}

char* Fifo::write(int length) {
	mLength[mWriteCurrent] = length;
	sem_post(&mWriteToReadSem[mWriteCurrent]);
	mWriteCurrent = (mWriteCurrent + 1) % mNumBuffers;
	sem_wait(&mReadToWriteSem[mWriteCurrent]);
	return mBuffer[mWriteCurrent];
}

char* Fifo::read(int* length) {
	static bool firstTime = true;
	if (!firstTime) {
		sem_post(&mReadToWriteSem[mReadCurrent]);
	}
	firstTime = false;
	mReadCurrent = (mReadCurrent + 1) % mNumBuffers;
	sem_wait(&mWriteToReadSem[mReadCurrent]);
	*length = mLength[mReadCurrent];
	return mBuffer[mReadCurrent];
}