forked from knobli/c_programming
-
Notifications
You must be signed in to change notification settings - Fork 0
/
characterCounter.c
218 lines (185 loc) · 5.83 KB
/
characterCounter.c
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#define SEMPERM 0600
#define PERM 0600
#define ERROR_SIZE 16384
int shmid_for_cleanup = 0;
int semid_for_cleanup = 0;
struct data {
long counter[256];
};
const int SIZE = sizeof(struct data);
void handle_error(int return_code, const char *msg);
int create_sem(const char *txt, const char *etxt);
int create_shm(const char *txt, const char *etxt);
void show_shm_ctl(int shm_id, const char *txt);
void *readFile(char *fileName, struct data *shm_data, int sem_id);
void increaseCharCount(unsigned char c, struct data *shm_data, int sem_id);
void printResult(struct data *shm_data);
void printResultOfChar(unsigned char c, struct data *shm_data);
void cleanup() {
if (shmid_for_cleanup > 0) {
int retcode = shmctl(shmid_for_cleanup, IPC_RMID, NULL);
handle_error(retcode, "removing of shared memory failed");
shmid_for_cleanup = 0;
}
if (semid_for_cleanup > 0) {
int retcode = semctl(semid_for_cleanup, 1, IPC_RMID, 0);
handle_error(retcode, "removing of semaphore failed");
semid_for_cleanup = 0;
}
}
/* helper function for dealing with errors */
void handle_error(int return_code, const char *msg) {
if (return_code < 0) {
char extra_txt[ERROR_SIZE];
char error_msg[ERROR_SIZE];
char *extra_msg = extra_txt;
int myerrno = errno;
const char *error_str = strerror(myerrno);
if (msg != NULL) {
sprintf(extra_msg, "%s\n", msg);
} else {
extra_msg = "";
}
sprintf(error_msg, "%sreturn_code=%d\nerrno=%d\nmessage=%s\n", extra_msg, return_code, myerrno, error_str);
write(STDOUT_FILENO, error_msg, strlen(error_msg));
cleanup();
exit(1);
}
}
int main(int argc, char *argv[]) {
if(argc != 2){
printf("Please enter a file name\n");
exit(1);
}
printf("This programm use semaphore and shared memory, please cleanup after testing\n");
int sem_id = create_sem("create semaphore", "semget failed");
semid_for_cleanup = sem_id;
int i;
for(i = 0; i < 250; i++){
int retcode = semctl(sem_id, i, SETVAL , 1);
if(retcode < 0){
printf("Init semaphore %d\n", i);
handle_error(retcode, "Could not initialize semaphore to 1");
}
}
int shm_id = create_shm("create shared memory", "shmget failed");
struct data *shm_data = (struct data *) shmat(shm_id, NULL, 0);
show_shm_ctl(shm_id, "Show shared memory information:");
shmid_for_cleanup = shm_id;
printf("Start reading\n");
readFile(argv[1], shm_data, sem_id);
printf("Reading finished\n");
printResult(shm_data);
printf("Detach the shared memory\n");
shmdt(shm_data);
//cleanup();
exit(0);
}
void *readFile(char *fileName, struct data *shm_data, int sem_id)
{
if( access( fileName, F_OK ) == -1 ) {
printf("File does not exist\n");
exit(1);
}
FILE *file;
file = fopen(fileName, "r");
char inputChar = '\0';
while(inputChar != EOF){
inputChar = (char)fgetc(file);
increaseCharCount(inputChar, shm_data, sem_id);
};
}
void increaseCharCount(unsigned char c, struct data *shm_data, int sem_id){
if(c > 126 ){
//ignore characters bigger than 126
return;
}
struct sembuf sema;
int returnCode;
sema.sem_num = c - 1;
sema.sem_flg = SEM_UNDO;
sema.sem_op = -1;
returnCode=semop(sem_id, &sema, 1);
if(returnCode < 0){
printf("Catching semaphore %d\n", c - 1);
handle_error(returnCode, "Could not catch semaphore");
}
int currCounter = ++shm_data->counter[c];
//printf("Increase counter for %c (%d) and is now %d\n", c, c, currCounter);
struct timespec tim, tim2;
tim.tv_sec = 0;
tim.tv_nsec = 1000000;
nanosleep(&tim , &tim2);
sema.sem_op = 1;
returnCode=semop(sem_id, &sema, 1);
handle_error(returnCode, "Could not release semaphore");
}
int create_sem(const char *txt, const char *etxt){
FILE *f = fopen("semref.dat", "w");
fwrite("X", 1, 1, f);
fclose(f);
key_t sem_key = ftok("./semref.dat", 1);
handle_error(sem_key, "ftok for semaphore failed");
//only open 250 segments, because this is the maximum
//ipcs -ls
//------ Semaphore Limits --------
//max number of arrays = 128
//max semaphores per array = 250
//max semaphores system wide = 32000
//max ops per semop call = 32
//semaphore max value = 32767
int semaphore_id = semget(sem_key, 250, IPC_CREAT | SEMPERM);
handle_error(semaphore_id, etxt);
printf("%s: shm_id=%d key=%ld\n", txt, semaphore_id, (long) sem_key);
return semaphore_id;
}
int create_shm(const char *txt, const char *etxt) {
FILE *f = fopen("shmref.dat", "w");
fwrite("X", 1, 1, f);
fclose(f);
key_t shm_key = ftok("./shmref.dat", 1);
handle_error(shm_key, "ftok shared memory failed");
int shm_id = shmget(shm_key, SIZE, IPC_CREAT | PERM);
handle_error(shm_id, etxt);
printf("%s: shm_id=%d key=%ld\n", txt, shm_id, (long) shm_key);
return shm_id;
}
void show_shm_ctl(int shm_id, const char *txt) {
int retcode;
struct shmid_ds shmctl_data;
retcode = shmctl(shm_id, IPC_STAT, &shmctl_data);
handle_error(retcode, "child shmctl failed");
struct ipc_perm perms = shmctl_data.shm_perm;
printf("%s: key=%ld uid=%d gid=%d cuid=%d cgid=%d mode=%d seq=%d\n", txt, (long) perms.__key, (int) perms.uid, (int) perms.gid, (int) perms.cuid, (int) perms.cgid, (int) perms.mode, (int)perms.__seq);
}
void printResult(struct data *shm_data){
int i;
for(i=0; i < 250; i++){
printResultOfChar(i, shm_data);
}
}
void printResultOfChar(unsigned char c, struct data *shm_data){
int currCounter = shm_data->counter[c];
if(currCounter > 0){
if(c < 33 || c > 126 ){
printf("Counter for special character (%d) is now %d\n", c, currCounter);
} else {
printf("Counter for %c (%d) is: %d\n", c, c, currCounter);
}
}
}