Fix possible memory leak in allocmat()
[eleutheria.git] / pthreads / matrixmul.c
blob0d96ca85c491fae3f1a5869678858b39f3ff0a6f
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <pthread.h>
5 struct matrix {
6 unsigned int rows;
7 unsigned int cols;
8 int **data;
9 };
11 struct matrix_index {
12 unsigned int row;
13 unsigned int col;
16 struct matrix *mat1 = NULL;
17 struct matrix *mat2 = NULL;
18 struct matrix *mat3 = NULL;
20 typedef enum {
21 mm_error_none,
22 mm_error_no_memory,
23 mm_error_io
24 } mm_error;
26 /* function prototypes */
27 mm_error allocmat(struct matrix **mat, unsigned int rows, unsigned int cols);
28 void freemat(struct matrix **mat);
29 mm_error readmat(const char *path, struct matrix **mat);
30 void printmat(const struct matrix *mat);
31 void *mulvect(void *arg);
32 void diep(const char *s);
34 int main(int argc, char *argv[])
36 pthread_t *tid;
37 struct matrix_index *v;
38 unsigned int i, j, k, numthreads;
40 /* check argument count */
41 if (argc != 3) {
42 fprintf(stderr, "Usage: %s matfile1 matfile2\n", argv[0]);
43 exit(EXIT_FAILURE);
46 /* read matrix data from files */
47 readmat(argv[1], &mat1);
48 readmat(argv[2], &mat2);
50 /* is the multiplication feasible by definition? */
51 if (mat1->cols != mat2->rows) {
52 fprintf(stderr, "Matrices' dimensions size must satisfy (NxM)(MxK)=(NxK)\n");
53 exit(EXIT_FAILURE);
56 /* allocate memory for the result */
57 allocmat(&mat3, mat1->rows, mat2->cols);
59 /* how many threads do we need ?*/
60 numthreads = mat1->rows * mat2->cols;
62 /* v[k] holds the (i, j) pair in the k-th computation */
63 if ((v = malloc(numthreads * sizeof(struct matrix_index))) == NULL)
64 diep("malloc");
66 /* allocate memory for the threads' ids */
67 tid = malloc(numthreads * sizeof(pthread_t));
68 if (tid == NULL) {
69 fprintf(stderr, "Error allocating memory\n");
70 exit(EXIT_FAILURE);
73 /* create the threads */
74 for (i = 0; i < mat1->rows; i++) {
75 for (j = 0; j < mat2->cols; j++) {
76 k = i*mat1->rows + j;
77 v[k].row = i;
78 v[k].col = j;
79 if (pthread_create(&tid[k], NULL, mulvect, (void *)&v[k])) {
80 fprintf(stderr, "pthtrad_create() error\n");
81 exit(EXIT_FAILURE);
86 /* make sure all threads are done */
87 for (i = 0; i < numthreads; i++)
88 if (pthread_join(tid[i], NULL)) {
89 fprintf(stderr, "pthread_join() error\n");
90 exit(EXIT_FAILURE);
93 /* print the result */
94 printmat(mat3);
96 /* free matrices */
97 freemat(&mat1);
98 freemat(&mat2);
99 freemat(&mat3);
101 return EXIT_SUCCESS;
104 mm_error allocmat(struct matrix **mat, unsigned int rows, unsigned int cols)
106 unsigned int i, j, mdepth = 0;
108 *mat = malloc(sizeof **mat);
109 if (*mat == NULL) {
110 perror("malloc");
111 goto CLEANUP_AND_RETURN;
113 mdepth++;
115 (*mat)->rows = rows;
116 (*mat)->cols = cols;
118 (*mat)->data = malloc(rows * sizeof(int *));
119 if ((*mat)->data == NULL) {
120 perror("malloc");
121 goto CLEANUP_AND_RETURN;
123 mdepth++;
125 for (i = 0; i < rows; i++) {
126 (*mat)->data[i] = malloc(cols * sizeof(int));
127 if ((*mat)->data[i] == NULL) {
128 perror("malloc");
129 if (i != 0)
130 mdepth++;
131 goto CLEANUP_AND_RETURN;
134 return mm_error_none;
136 CLEANUP_AND_RETURN:;
137 switch(mdepth) {
138 case 3:
139 for (j = 0; j < i; j++)
140 free((*mat)->data[j]);
141 case 2:
142 free((*mat)->data);
143 case 1:
144 free(*mat);
145 case 0:
146 ; /* free nothing */
149 return mm_error_no_memory;
152 void freemat(struct matrix **mat)
154 unsigned int i;
156 for (i = 0; i < (*mat)->rows; i++) {
157 if ((*mat)->data[i] != NULL)
158 free((*mat)->data[i]);
161 if (*mat != NULL)
162 free(*mat);
164 *mat = NULL;
167 mm_error readmat(const char *path, struct matrix **mat)
169 FILE *fp;
170 unsigned int i, j, rows, cols;
172 /* open file */
173 if ((fp = fopen(path, "r")) == NULL) {
174 fprintf(stderr, "Error opening file: %s\n", path);
175 return mm_error_io;
178 /* read matrix dimensions */
179 fscanf(fp, "%u%u", &rows, &cols);
181 /* allocate memory for matrix */
182 allocmat(mat, rows, cols);
184 /* read matrix elements */
185 for (i = 0; i < (*mat)->rows; i++) {
186 for (j = 0; j < (*mat)->cols; j++) {
187 fscanf(fp, "%d", &(*mat)->data[i][j]);
191 /* close file */
192 fclose(fp);
194 return mm_error_none;
198 void printmat(const struct matrix *mat)
200 unsigned int i, j;
202 for (i = 0; i < mat->rows; i++) {
203 for (j = 0; j < mat->cols; j++) {
204 printf("%d ", mat->data[i][j]);
206 printf("\n");
211 void *mulvect(void *arg) {
212 unsigned int i, row, col;
214 row = *((int *)arg + 0);
215 col = *((int *)arg + 1);
217 mat3->data[row][col] = 0;
218 for (i=0; i<mat1->cols; i++)
219 mat3->data[row][col] += mat1->data[row][i] * mat2->data[i][col];
221 pthread_exit(NULL);
224 void diep(const char *s)
226 perror(s);
227 exit(EXIT_FAILURE);