-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathread.c
More file actions
165 lines (134 loc) · 5.19 KB
/
read.c
File metadata and controls
165 lines (134 loc) · 5.19 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "head.h"
int main(int argc, char *argv[])
{
/**
* Takes the arguments in the command line and integer 'ringBufferSize'
* gets assigned a size for the memory.
*
* put ':' at the starting of the string so compiler can distinguish between '?' and ':' .
*/
while ((option = getopt(argc, argv, ":m:")) != -1) { //get option from the getopt() method
switch (option){
case 'm':
ringBufferSize = strtol(optarg, &p, 10);
if(ringBufferSize <= 0){
fprintf(stderr,"Ring buffer size must be > 0!\n");
break;
}
break;
case ':':
fprintf(stderr,"Option needs a value!\n");
break;
case '?':
fprintf(stderr,"Unknown option: %c!\n", optopt);
break;
}
}
/**
* All references are removed from the semaphores.
* This gives us a clean "start".
*/
sem_unlink(SEMAPHORE_ZERO);
sem_unlink(SEMAPHORE_OCCUPIED);
/**
* Request a key.
* The key is linked to a filename,
* so that other programs can access it.
*/
key = ftok(FILENAME, 0);
if (key == IPC_REST_ERROR) {
return IPC_REST_ERROR;
}
/**
* Get shared memory block - Create it, if it doesn't exist
* and returns a valid shared memory identifier. On error, -1
*/
int shared_block_id = shmget(key, ringBufferSize, 0644 | IPC_CREAT);
if (shared_block_id == IPC_REST_ERROR) {
return IPC_REST_ERROR;
}
/**
* Map the shared block into the address space of the calling process
* and give me a pointer to it.
*/
addressSpace = shmat(shared_block_id, NULL, 0);
if (addressSpace == (char *)IPC_REST_ERROR) {
return IPC_REST_ERROR;
}
/* A new semaphore is created or an existing one is opened, Init value set to 0. */
sem_t *sem_read = sem_open(SEMAPHORE_ZERO, O_CREAT, S_IRWXU | S_IRWXG, 0);
if (sem_read == SEM_FAILED) {
fprintf(stderr, "ERROR with sem_open SEMAPHORE_ZERO: %s\n", strerror(errno));
return IPC_REST_ERROR;
}
/* A new semaphore is created or an existing one is opened, Init value set to the ringBufferSize. */
sem_t *sem_write = sem_open(SEMAPHORE_OCCUPIED, O_CREAT, S_IRWXU | S_IRWXG, ringBufferSize);
if (sem_write == SEM_FAILED) {
fprintf(stderr, "ERROR with sem_open SEMAPHORE_OCCUPIED: %s\n", strerror(errno));
return IPC_REST_ERROR;
}
/* We store here the first and last address of our created memory area to create the ring buffer. */
addressSpaceHead = addressSpace;
addressSpaceTail = (addressSpace + ringBufferSize - 1);
/**
* Here is a while(1) created because we cannot
* know in advance when the input of the STDIN (EOF) is reached.
*/
while (1){
/* Decrement 'sem_write' -1 and read in the first character (byte) */
while (sem_wait(sem_write) == -1){
/**
* Many system calls will report the 'EINTR' error code if a signal occurred while the system call was in progress.
* No error actually occurred, it's just reported that way because the system isn't able to resume the system call automatically.
*/
if(errno != EINTR){
fprintf(stderr,"Error with sem_write: %s\n",strerror(errno));
return -1;
}
}
/**
* We check errors while printing the read characters to STDOUT
* and 'clearerr' is needed to detect this. The function clearerr() clears
* the end-of-file and error indicators for the stream pointed to by STREAM.
*/
clearerr(stdin);
if((*addressSpace = getc(stdin)) == EOF){
if(ferror(stdin) != 0){ //return the error indicator for the STREAM
fprintf(stderr,"Error while reading from STDIN: %s",strerror(errno));
return -1;
}
}
/* When reading of the characters is finished (EOF), sem_read is released and incremented. We leave the while. */
if(*addressSpace == EOF){
if(sem_post(sem_read) == -1){
fprintf(stderr,"Error with sem_read: %s",strerror(errno));
return -1;
}
break;
}
/* Our created shared memory ring buffer */
if (addressSpace != addressSpaceTail){
addressSpace += 1;
}
else{
addressSpace = addressSpaceHead;
}
/*
* Now I release sem_read and increment from 0 to 1 and program 'write' can step into the critical section and read
* the character from the ring buffer into e.g. a textfile .
*/
if(sem_post(sem_read) == -1){
fprintf(stderr,"Error with sem_read: %s",strerror(errno));
return -1;
}
}
/**
* shmctl: Shared memory control operation
* IPC_RMID: Mark the segment to be destroyed. The segment will actually
* be destroyed only after the last process detaches it.
*/
if(shmctl(shared_block_id, IPC_RMID, NULL) == -1 ) {
return IPC_REST_ERROR;
}
return 0;
}