Change return type from int to void for
start_task_on_worker() and fetch_output_from_worker().
There is no necessity to return an integer since they handle failures and their
callers don't get much out of knowing if they succeeded or failed.
Differentiate between application and system level failures when starting tasks
on workers. Propagate these failures all the way up to start_task_on_worker()
where failures are currently handled.
Use the total bytes returned as sent in debugging.
On application-level failure in sending an input file, describe the file as
missing.
Differentiate between app and sys level failures
when retrieving output files from workers. Propagate these failures all the way
up to fetch_output_from_worker() where failures are currently handled.
Update code to check for new return values from
get_output_files().
Add handle_app_failure() & handle_worker_failure().
All failures now go through handle_failure().  It calls handle_app_failure() and
handle_worker_failure() based on the type of failure. This simplifies code and
removes the use of goto.
Proceed to get other output files even if there was an app-level failure in getting
one of them.
Catch memory allocation failures before access.
Also update the functions to return a value signaling this failure.
Clean up WQ_RESULT_* codes. Expose them to user.
The WQ_RESULT_* codes will only signal app-level failures.
Remove WQ_RESULT_FUNCTION_FAIL.
We already return the task exit code as return_status. So the application can
check to see if the return_status indicates task execution failure.
Update the local data structure when we evict files from the worker's cache.