void * output_worker(void * voided_param) { crypter_t * io_worker = (crypter_t *)voided_param; while (has_more_input || io_worker -> current_task != NULL) { if (io_worker -> current_task == NULL || !(io_worker -> current_task -> complete)) sched_yield(); else { output_task(io_worker -> current_task); if (pthread_mutex_lock(&(io_worker -> mutex))) perror("io_worker lock failed in output_worker"); crypttask_t * oldtask = io_worker -> current_task; io_worker -> current_task = io_worker -> current_task -> next_block; io_worker -> num_tasks--; pthread_mutex_unlock(&(io_worker -> mutex)); free(oldtask -> text); free(oldtask); } } return NULL; }
int main(int argc, char **argv) { try { // First thing, set up logging. Logger::Init(argv[0]); // We'll keep the scanner threads in this vector so we can join() them later. std::vector<std::thread> scanner_threads; // Instantiate classes for file and directory inclusion/exclusion management. TypeManager type_manager; DirInclusionManager dir_inclusion_manager; // Instantiate the argument parser. ArgParse arg_parser(type_manager); // Parse command-line options and args. arg_parser.Parse(argc, argv); dir_inclusion_manager.AddExclusions(arg_parser.m_excludes); type_manager.CompileTypeTables(); dir_inclusion_manager.CompileExclusionTables(); LOG(INFO) << "Num scanner jobs: " << arg_parser.m_jobs; // Create the Globber->FileScanner queue. sync_queue<FileID> files_to_scan_queue; // Create the FileScanner->OutputTask queue. sync_queue<MatchList> match_queue; // Set up the globber. Globber globber(arg_parser.m_paths, type_manager, dir_inclusion_manager, arg_parser.m_recurse, arg_parser.m_follow_symlinks, arg_parser.m_dirjobs, files_to_scan_queue); // Set up the output task object. OutputTask output_task(arg_parser.m_color, arg_parser.m_nocolor, arg_parser.m_column, match_queue); // Create the FileScanner object. std::unique_ptr<FileScanner> file_scanner(FileScanner::Create(files_to_scan_queue, match_queue, arg_parser.m_pattern, arg_parser.m_ignore_case, arg_parser.m_word_regexp, arg_parser.m_pattern_is_literal)); // Start the output task thread. std::thread output_task_thread {&OutputTask::Run, &output_task}; // Start the scanner threads. for(int t=0; t<arg_parser.m_jobs; ++t) { std::thread fst {&FileScanner::Run, file_scanner.get(), t}; scanner_threads.push_back(std::move(fst)); } // Start the globber threads last. // We do this last because the globber is the ultimate source for the work queue; all other threads will be // waiting for it to start sending data to the Globber->FileScanner queue. If we started it // first, the globbing would start immediately, and it would take longer to get the scanner and output // threads created and started, and ultimately slow down startup. // Note that we just call globber.Run() here. It blocks, spawning and managing its own threads until the directory // tree traversal is complete. globber.Run(); // Close the Globber->FileScanner queue. files_to_scan_queue.close(); // Wait for all scanner threads to complete. for (auto& scanner_thread_ref : scanner_threads) { scanner_thread_ref.join(); } // All scanner threads completed. // Close the FileScanner->OutputTask queue. match_queue.close(); // Wait for the output thread to complete. output_task_thread.join(); auto total_matched_lines = output_task.GetTotalMatchedLines(); if(total_matched_lines == 0) { // No matches, return a grep-compatible 1. return 1; } else { // Found some matches, return success. return 0; } } catch(const FileScannerException &e) { ERROR() << "Error during regex parsing: " << e.what(); return 255; } catch(const ArgParseException &e) { ERROR() << "Error during arg parsing: " << e.what(); return 255; } catch(const std::runtime_error &e) { ERROR() << "std::runtime_error exception: " << e.what(); return 255; } catch(...) { // We shouldn't need this catch(...), but Cygwin seems to not properly call the default // terminate handler (which should be abort()) if we let an exception escape main(), but will simply return // without an error code. I ran into this when trying to instantiate std::locale with locale=="" in ArgParse, // and before I had the std::runtime_error catch clause above. ERROR() << "Unknown exception occurred."; std::abort(); } }
int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { int result = parse_args (argc, argv); if (result != 0) { return result; } ACE_High_Res_Timer::calibrate (); // Create the message queue Message_Queue input_message_queue; Message_Queue output_message_queue; // Create the datablocks. IF we use the default Message Blocks Ctor, // it is going to do an extra allocation for the data block ACE_NEW_RETURN (data_block, ACE_Locked_Data_Block<ACE_Lock_Adapter<ACE_SYNCH_MUTEX> >, -1); // Increment the reference count so that we can share the // datablock. This is donw twice the number of messages for the // input and output queues. size_t i = 0; for (i = 0; i < 2*number_of_messages; ++i) { data_block->duplicate (); } // Create the Synchronisers Synchronisers synch; // Workers. Worker_Task **workers = 0; ACE_NEW_RETURN (workers, Worker_Task *[number_of_workers], -1); // Input Task Input_Task input_task (&input_message_queue, synch); // Output Task Output_Task output_task (&output_message_queue, synch); int priority = ACE_Sched_Params::priority_max (ACE_SCHED_FIFO); long flags = THR_SCHED_FIFO | THR_SCOPE_PROCESS; // Create and activate the worker threads for (i = 0; i < number_of_workers; ++i) { ACE_NEW_RETURN (workers[i], Worker_Task (&input_message_queue, synch), -1); workers[i]->next (&output_task); // Activate the workers. result = workers[i]->activate (flags, 1, 1, priority); if (result != 0) { flags = THR_BOUND; priority = ACE_Sched_Params::priority_min (ACE_SCHED_OTHER, ACE_SCOPE_THREAD); result = workers[i]->activate (flags, 1, 1, priority); if (result != 0) { return result; } } } // Activate the input and output threads result = input_task.activate (flags, 1, 1, priority); if (result != 0) return result; // Activate the workers. result = output_task.activate (flags, 1, 1, priority); if (result != 0) return result; // Wait for all threads to terminate. result = ACE_Thread_Manager::instance ()->wait (); ACE_hrtime_t elapsed_time = 0; test_timer.elapsed_time (elapsed_time); # if !defined (ACE_WIN32) double elapsed_time_per_invocation = (double) elapsed_time / number_of_messages; ACE_DEBUG ((LM_DEBUG, "(%P|%t) Throughput is [%f] \n", elapsed_time_per_invocation)); ACE_DEBUG ((LM_DEBUG, "(%P|%t) Throughput is [%f] \n", 1000000000/ elapsed_time_per_invocation)); #endif /*ACE_WIN32 */ for (i = 0; i < number_of_workers; ++i) { ACE_DEBUG ((LM_DEBUG, "Message process for thread [%d] is [%d] \n", i, workers[i]->processed ())); delete workers[i]; } delete[] workers; return result; }