View difference between Paste ID: Kmp5dUPL and vxWnqttB
SHOW: | | - or go back to the newest paste.
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <pthread.h>
4
#include <errno.h>
5
#include <string.h>
6
#include <sys/types.h>
7
#include <sys/stat.h>
8
#include <fcntl.h>
9
#include <unistd.h>
10
#include <time.h>
11
12
int thread_quantity;
13
int buffer_size;
14
char *requested_file_name;
15
char *requested_word;
16
17
int file_des = 0;
18
int created_threads = 0;
19
int alive_threads;
20
21
pthread_mutex_t reading_mutex = PTHREAD_MUTEX_INITIALIZER;
22
pthread_t *thread_id = NULL;
23
off_t file_size;
24
pthread_key_t buffer;
25
26
void usage() {
27
exit(1);
28
}
29
void err_exit(char *);
30
void* thread_function(void *);
31
void clean_thread(void *);
32
void clean_tsd_buffer(void *); //thread specific data
33
//############################################################
34
int main(int argc, char *argv[]) {
35
	int i;
36
	if (argc != 5) {
37
		usage();
38
	} else {
39
		thread_quantity = (int) strtol(argv[1], NULL, 10);
40
		alive_threads = thread_quantity;
41
		thread_id = malloc(sizeof(pthread_t) * thread_quantity);
42
		requested_file_name = argv[2];
43
		buffer_size = (int) strtol(argv[3], NULL, 10);
44
		if (errno) {
45
			usage();
46
		}
47
		requested_word = argv[4];
48
	}
49
	if ((file_des = open(requested_file_name, O_RDONLY)) == -1) {
50
		err_exit("Error: open(requested_file_name)");
51
	}
52
	if ((file_size = lseek(file_des, 0, SEEK_END)) == (off_t) -1) {
53
		err_exit("Error: lseek(file_des, 0, SEEK_END)");
54
	}
55
	if (lseek(file_des, 0, SEEK_SET) == (off_t) -1) {
56
		err_exit("Error: lseek(file_des, 0, SEEK_END)");
57
	}
58
	if (pthread_mutex_init(&reading_mutex, NULL) != 0) {
59
		err_exit("Error: pthread_mutex_init(reading_mutex)");
60
	}
61
	if (pthread_key_create(&buffer, clean_tsd_buffer)) {
62
		err_exit("Error: pthread_key_create()");
63
	}
64
	//=========================================================
65
	for (i = 0; i < thread_quantity; i++) {
66
		if (pthread_create(&thread_id[i], NULL, thread_function, NULL)) {
67
			err_exit("Error: pthread_create()");
68
		} else {
69
			created_threads++;
70
		}
71
	}
72
	while (alive_threads) {
73
		usleep(1000);
74
	}
75
	for (i = 0; i < thread_quantity; i++) {
76
		if (pthread_join(thread_id[i], NULL)) {
77
			err_exit("Error: pthread_join()");
78
		}
79
	}
80
	//=========================================================
81
	err_exit(NULL);
82
	return EXIT_SUCCESS;
83
}
84
//############################################################
85
void clean_tsd_buffer(void *arg) {
86
	if (arg != NULL) {
87
		free(arg);
88
	}
89
}
90
void clean_thread(void *arg) {
91
	alive_threads--;
92
}
93
//-----------------------------------------------------------
94
void *thread_function(void *data) {
95
	pthread_cleanup_push(clean_thread, NULL);
96
				if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
97
					err_exit("Error: pthread_setcanceltype()");
98
				}
99
				if (pthread_setspecific(buffer, malloc(sizeof(char) * buffer_size))) {
100
					err_exit("Error: pthread_setspecific()");
101
				}
102
				int i, bytes_readed;
103
				off_t jump, current_offset;
104
				void *cbuffer = pthread_getspecific(buffer);
105
				for (i = 0; i < thread_quantity; i++) {
106
					if (pthread_equal(pthread_self(), thread_id[i])) {
107
						jump = (off_t) i * buffer_size;
108
						break;
109
					}
110
				}
111
				//==========================================================
112
				while (1) {
113
					if (pthread_mutex_lock(&reading_mutex) != 0) {
114
						err_exit("Error: pthread_mutex_lock(reading_mutex)");
115
					}
116
					if ((current_offset = lseek(file_des, jump, SEEK_SET)) == (off_t) -1) {
117
						err_exit("Error: lseek(reading_mutex)");
118
					}
119
					if (current_offset > file_size) {
120
						if (pthread_mutex_unlock(&reading_mutex) != 0) {
121
							err_exit("Error: pthread_mutex_unlock(reading_mutex)");
122
						}
123
						if (pthread_cancel(pthread_self())) {
124
							err_exit("Error: pthread_cancel()");
125
						}
126
					} else {
127
						bytes_readed = read(file_des, cbuffer, buffer_size);
128
					}
129
					if (pthread_mutex_unlock(&reading_mutex) != 0) {
130
						err_exit("Error: pthread_mutex_unlock(reading_mutex)");
131
					}
132
					usleep(50);
133
					if (bytes_readed > 0) {
134
                        //no, don't need that code
135
					} else if (!bytes_readed) {
136
						if (pthread_cancel(pthread_self())) {
137
							err_exit("Error: pthread_cancel()");
138
						}
139
					} else { // Error
140
						err_exit("Error: czytanie z pliku w wÄ…tku");
141
					}
142
					jump += thread_quantity * buffer_size;
143
				}
144
				//==========================================================
145
				pthread_cleanup_pop(1);
146
	if (pthread_cancel(pthread_self())) {
147
		err_exit("Error: pthread_cancel()");
148
	}
149
	return data;
150
}
151
//-----------------------------------------------------------
152
void err_exit(char *msg) {
153
	if (msg != NULL) {
154
		perror(msg);
155
		sleep(10);
156
	}
157
	if (file_des != 0) {
158
		if (close(file_des) == -1) {
159
			perror("Error: close(file_des)");
160
		}
161
	}
162
	if (thread_id != NULL) {
163
		free(thread_id);
164
	}
165
	exit(1);
166
}
167
168
169
170
171
172
173
/////////////////////////////////////####################### test.txt #################
174
The pthread_cleanup_push() function pushes routine onto the top of  the
175
       stack  of clean-up handlers.  When routine is later invoked, it will be
176
       given arg as its clean argument.
177
       The pthread_cleanup_pop() function removes the routine at  the  top  of
178
       the  stack  of clean-up handlers, and optionally executes it if execute
179
       is nonzero. 
180
181
       A cancellation clean-up handler is popped from the stack  and  executed
182
       in the following circumstances:
183
184
       1. When  a thread is canceled, all of the stacked clean-up handlers are
185
          popped and executed in the reverse of the order in which  they  were
186
          pushed onto the stack.
187
188
       2. When  a  thread  terminates by calling pthread_exit(3), all clean-up
189
          handlers are executed as described in the preceding point.   (Clean-
190
          up  handlers are not called if the thread terminates by performing a
191
          return from the thread start function.) clean
192
193
       3. When a thread calls pthread_cleanup_pop()  with  a  nonzero  execute
194
          argument, the top-mst clean-up handler is popped and executed.
195
196
       POSIX.1  permits pthread_cleanup_push() and pthread_cleanup_pop() to be
197
       implemented as macros that expand  to  text  containing  '{'  and  '}',
198
       respectively.   For  this  reason, the caller must ensure that call