which crew members wait to receive new work (go).
43-44 The allowed size of a file name and path name may vary depending on the file system to which the path leads. When a crew is started, the program calculates the allowable file name and path length for the specified file path by calling path-conf, and stores the values in path_max and name_max, respectively, for later use.
1 #include <sys/types.h>
2 #include <pthread.h>
3 #include <sys/stat.h>
4 #include <dirent.h>
5 #include 'errors.h'
6
7 #define CREW_SIZE 4
8
9 /*
/*
10 * Queued items of work for the crew. One is queued by
11 * crew_start, and each worker may queue additional items.
12 */
13 typedef struct work_tag {
14 struct work_tag *next; /* Next work item */
15 char *path; /* Directory or file */
16 char *string; /* Search string */
17
18
19 } work_t, *work_p;
/*
20 * One of these is initialized for each worker thread in the
21 * crew. It contains the 'identity' of each worker.
22 */
23 typedef struct worker_tag {
24 int index; /* Thread's index */
25 pthread_t thread; /* Thread for stage */
26 struct crew_tag *crew; /* Pointer to crew */
27 } worker_t, *worker_p;
28
29 /*
30 * The external 'handle' ' for a work crew. Contains the
31 * crew synchronization state and staging area.
32 */
33 typedef struct crew_tag {
34 int crew_size; /* Size of array */
35 worker_t crew[CREW_SIZE];/* Crew members */
36 long work_count; /* Count of work items */
37 work_t *first, *last; /* First & last work item */
38 pthread_mutex_t mutex; /* Mutex for crew data */
39 pthread_cond_t done; /* Wait for crew done */
40 pthread_cond_t go; /* Wait for work */
41
42 } crew_t, *crew_p;
43 size_t path_max; /* Filepath length */
44 size t name max; /* Name length */
Part 2 shows worker_routine, the start function for crew threads. The outer loop repeats processing until the thread is told to terminate.
20-23 POSIX is a little ambiguous about the actual size of the struct dirent type. The actual requirement for readdir_r is that you pass the address of a buffer large enough to contain a struct dirent with a name member of at least NAME_ MAX bytes. To ensure that we have enough space, allocate a buffer the size of the system's struct dirent plus the maximum size necessary for a file name on the file system we're using. This may be bigger than necessary, but it surely won't be too small.
33-37 This condition variable loop blocks each new crew member until work is made available.
61-65 This wait is a little different. While the work list is empty, wait for more work. The crew members never terminate—once they're all done with the current assignment, they're ready for a new assignment. (This example doesn't take advantage of that capability — the process will terminate once the single search command has completed.)
73-76 Remove the first work item from the queue. If the queue becomes empty, also clear the pointer to the last entry, crew->last.
81-83 Unlock the work crew mutex, so that the bulk of the crew's work can proceed concurrently.
89 Determine what sort of file we've got in the work item's path string. We use lstat, which will return information for a symbolic link, rather than stat, which would return information for the file to which the link pointed. By not following symbolic links, we reduce the amount of work in this example, and, especially, avoid following links into other file systems where our name_max and path_max sizes may not be sufficient.
91-95 If the file is a link, report the name, but do nothing else with it. Note that each message includes the thread's work crew index (mine->index), so that you can easily see 'concurrency at work' within the example.
96-165 If the file is a directory, open it with opendir. Find all entries in the directory by repeatedly calling readdir_r. Each directory entry is entered as a new work item.
166-206 If the file is a regular file, open it and read all text, looking for the search string. If we find it, write a message and exit the search loop.
207-218 If the file is of any other type, write a message attempting to identify the type.
232-252 Relock the work crew mutex, and report that another work item is done. If the count reaches 0, then the crew has completed the assignment, and we broadcast to awaken any threads waiting to issue a new assignment. Note that the work count is decreased only after the work item is fully processed — the count will never reach 0 if any crew member is still busy (and might queue additional directory entries).
¦ crew.c part 2 worker_routine
1 /*
2 * The thread start routine for crew threads. Waits until 'go'
3 * command, processes work items until requested to shut down.
4 */
5 void *worker_routine (void *arg)
6 {
7 worker_p mine = (worker_t*)arg;
8 crew_p crew = mine->crew;
9 work_p work, new_work;
10 struct stat filestat;
11 struct dirent *entry;
12 int status; 13
14 /*