summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.hp/quicksort.c
blob: b44b828a8d5b5964c682e059074edcffa3bf9861 (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
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* BeginSourceFile quicksort.c

  This file is take from the DDE test system.  It spawns six
  threads to do a sort of an array of random numbers.

  The locations marked "quick N" are used in the test "quicksort.exp".

  The locations marked "att N" are used in the test "attach.exp".

  To compile:

      cc -Ae +DA1.0 -g -o quicksort -lpthread quicksort.c

  To run:
  
     quicksort     --normal run
     quicksort 1   --waits before starting to allow attach
*/

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>

#define TRUE 1
#define FALSE 0
#define SORTSET 100000

/* Uncomment to turn on debugging output */
/* #define QUICK_DEBUG  */

/* Uncomment to turn on wait on each thread create */
/* #define THREAD_WAIT */

/* Fewer than SORT_DIRECT items are sorted with an insertion sort. */
#define SORT_DIRECT 20

/* Work at this depth or less generates a separate work item. */
#define DEFER_DEPTH 6

/* Workpile controller */
typedef void (*work_proc_t)(void *);

typedef struct workpile_struct {
	pthread_mutex_t lock;	       /* mutex for this structure */
	pthread_cond_t work_wait;      /* workers waiting for work */
	pthread_cond_t finish_wait;    /* to wait for workers to finish */
	int max_pile;		       /* length of workpile array */
	work_proc_t worker_proc;       /* work procedure */
	int n_working;		       /* number of workers working */
	int n_waiting;		       /* number of workers waiting for work */
	int n_pile;		       /* number of pointers in the workpile */
	int inp;		       /* FIFO input pointer */
	int outp;		       /* FIFO output pointer */
	void *pile[1];		       /* array of pointers - the workpile */
} *workpile_t;

typedef struct {
	float *data;		   /* Array to sort */
	int n;			   /* Number of elements in the array */
	int depth;		   /* Depth of recursion */
	workpile_t wp;		   /* Workpile to use */
} quick_sort_args;

/* True if waiting for attach.
 */
int wait_here = FALSE;

static workpile_t quick_sort_workpile = NULL;

void *worker(void * wptr);

/* Allocates and initializes a workpile that holds max_pile entries.
 * worker_proc is called to process each work item on the queue.
 */
workpile_t
work_init(int max_pile, work_proc_t worker_proc, int n_threads)
{
	int err;
	pthread_t t;
	workpile_t wp = (workpile_t)
		malloc(sizeof (struct workpile_struct) +
			(max_pile * sizeof (void *)));

	if (wp != NULL) {
		pthread_mutex_init(&wp->lock, NULL);
		pthread_cond_init(&wp->work_wait, NULL);
		pthread_cond_init(&wp->finish_wait, NULL);
		wp->max_pile = max_pile;
		wp->worker_proc = worker_proc;
		wp->n_working = wp->n_waiting = wp->n_pile = 0;
		wp->inp = wp->outp = 0;
		while (n_threads--) {
			err = pthread_create(&t, NULL,
			      worker, (void *)&wp);
#ifdef QUICK_DEBUG
                        printf( "== Quicksort: created new thread\n" );
#ifdef THREAD_WAIT
                        if( n_threads > 0 ) {
                            int i;
                        printf( "== Quicksort: waiting on user input of an integer\n" );
                            scanf( "%d", &i );
                            printf( "== Quicksort: continuing with quicksort\n" );
                        }
#endif
#endif

			assert(err == 0);    /* quick 1 */
		}
                /* All the threads have now been created.
                 */
                assert( n_threads == -1 );         /* att 1 */
                if( wait_here ) {
#ifdef QUICK_DEBUG
                    printf( "== Quicksort: waiting for attach\n" );
#endif
                    sleep( 25 );
                }
                wait_here = 99;              /* att 2, otherwise useless */
	}
	return (wp);                         /* quick 2 */
}

/*
 * Worker thread routine. Continuously looks for work, calls the
 * worker_proc associated with the workpile to do work.
 */
void *
worker(void * wptr)
{
        workpile_t wp;
	void *ptr;

        wp = * (workpile_t *) wptr;

	pthread_mutex_lock(&wp->lock);
	wp->n_working++;
	for (;;) {
		while (wp->n_pile == 0) {								/* wait for new work */
			if (--wp->n_working == 0)
				pthread_cond_signal(&wp->finish_wait);
			wp->n_waiting++;
			pthread_cond_wait(&wp->work_wait, &wp->lock);
			wp->n_waiting--;       /* quick 3 */
			wp->n_working++;
		}
		wp->n_pile--;
		ptr = wp->pile[wp->outp];
		wp->outp = (wp->outp + 1) % wp->max_pile;
		pthread_mutex_unlock(&wp->lock);
		/* Call application worker routine. */
		(*wp->worker_proc)(ptr);
		pthread_mutex_lock(&wp->lock);  /* quick 4 */
	}
	/* NOTREACHED */
}

/* Puts ptr in workpile. Called at the outset, or within a worker. */
void
work_put(workpile_t wp, void *ptr)
{
	pthread_mutex_lock(&wp->lock);
	if (wp->n_waiting) {
		/* idle workers to be awakened */
		pthread_cond_signal(&wp->work_wait);
	}
	assert(wp->n_pile != wp->max_pile);									/* check for room */
	wp->n_pile++;
	wp->pile[wp->inp] = ptr;
	wp->inp = (wp->inp + 1) % wp->max_pile;
	pthread_mutex_unlock(&wp->lock);
}


/* Wait until all work is done and workers quiesce. */
void
work_wait(workpile_t wp)
{
	pthread_mutex_lock(&wp->lock);
	while(wp->n_pile !=0 || wp->n_working != 0)
		pthread_cond_wait(&wp->finish_wait, &wp->lock);
	pthread_mutex_unlock(&wp->lock);
}

void
quick_sort_aux(float *data, int n, int depth, workpile_t wp, int deferrable)
{
	int i,j;

	/* If array small, use insertion sort */
	if (n <= SORT_DIRECT) {
		for (j = 1; j < n; j++) {
			/* data[0..j-1] in sort; find a spot for data[j] */
			float key = data[j];
			for (i = j - 1; i >= 0 && key < data[i]; i--)
				data[i+1] = data[i];
			data[i+1] = key;
		}
		return;
	}
	/* Defer this work to work queue if policy says so */
	if (deferrable && depth <= DEFER_DEPTH) {
		quick_sort_args *q = (quick_sort_args *)
								malloc(sizeof (quick_sort_args));
		assert(q != NULL);
		q->data = data; q->n = n; q->depth = depth; q->wp = wp;
		work_put(wp, (void *)q);
		return;
	}
	/* Otherwise, partition data based on a median estimate */
#define swap(i,j) {float t = data[i]; data[i] = data[j]; data[j] = t;}
	i = 0;
	j = n - 1;
	for (;;) {
		while (data[i] < data[j]) j--;
		if (i >= j) break;
		swap(i, j); i++;
		while (data[i] < data[j]) i++;
		if (i >= j) { i = j; break; }
		swap(i, j); j--;
	}
	/* Median value is now at data[i] */
	/* Partitioned so that data[0..i-1] <= median <= data[i+1..n-1] */
	quick_sort_aux(data,       i,     depth+1, wp, TRUE);
	quick_sort_aux(&data[i+1], n-i-1, depth+1, wp, TRUE);
}
/* Called from workpile controller with argument pointing to work. */
void
quick_sort_worker(void *a)
{
	quick_sort_args *q = (quick_sort_args *)a;
	quick_sort_aux(q->data, q->n, q->depth, q->wp, FALSE);
	free(q);
}
/* Main routine, called by client to do a sort. */
void
quick_sort(float *data, int n)
{
	if (quick_sort_workpile == NULL) {
		int n_threads = 6;
		quick_sort_workpile = work_init(2 << DEFER_DEPTH,
			quick_sort_worker, n_threads);
		assert(quick_sort_workpile != NULL);
	}
        
	quick_sort_aux(data, n, 0, quick_sort_workpile, FALSE);
        
	/* Wait for all work to finish */
	work_wait(quick_sort_workpile);
        
#ifdef QUICK_DEBUG
        printf( "== Quicksort: done sorting\n" );
#endif
}


main( argc, argv )
int    argc;
char **argv;
{
	float data[SORTSET];
	int i; int debugging = 0;

        if((argc > 1) && (0 != argv )) {
            if( 1 == atoi( argv[1] ) )
               wait_here = TRUE;
        }

	for(i = 0; i < SORTSET; i++)
		data[SORTSET -1 -i] = drand48();
                
	for(i = 0; i < SORTSET; i++)
		if (debugging)
                   printf("data[%d] = %f\n", i, data[i]);

	quick_sort(data, SORTSET);
	for(i = 0; i < SORTSET; i++)
		if (debugging)
		printf("data[%d] = %f\n", i, data[i]);

	return(0);
}
/* EndSourceFile */