[Swift-commit] cog r4026

swift at ci.uchicago.edu swift at ci.uchicago.edu
Wed Jul 16 22:30:04 CDT 2014


------------------------------------------------------------------------
r4026 | timgarmstrong | 2014-07-16 22:29:45 -0500 (Wed, 16 Jul 2014) | 1 line

Standardise on singular for coaster C interface
------------------------------------------------------------------------
Index: modules/provider-coaster-c-client/src/coaster.cpp
===================================================================
--- modules/provider-coaster-c-client/src/coaster.cpp	(revision 0)
+++ modules/provider-coaster-c-client/src/coaster.cpp	(revision 4026)
@@ -0,0 +1,752 @@
+/*
+ * Copyright 2014 University of Chicago and Argonne National Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/*
+ * Implementation of pure C functions.
+ *
+ * Created: Jun 18, 2014
+ *    Author: Tim Armstrong
+ */
+
+#include "coaster.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <pthread.h>
+
+#include "CoasterClient.h"
+#include "CoasterError.h"
+#include "CoasterLoop.h"
+#include "Settings.h"
+
+using namespace Coaster;
+
+using std::malloc;
+using std::free;
+
+using std::string;
+using std::memcpy;
+
+/*
+  Struct just wraps the objects
+ */
+struct coaster_client {
+  CoasterLoop loop;
+  CoasterClient client;
+
+  /*
+    Constructor: initialize loop then client
+   */
+  coaster_client(string serviceURL) :
+        loop(), client(serviceURL, loop) { }
+};
+
+struct coaster_err_info {
+  string msg;
+
+  coaster_err_info(const string _msg): msg(_msg) {}
+};
+
+static pthread_key_t err_key;
+static pthread_once_t err_key_init = PTHREAD_ONCE_INIT;
+
+static coaster_rc coaster_return_error(coaster_rc code,
+                                    const string &msg);
+static coaster_rc coaster_error_rc(const CoasterError &err);
+static coaster_rc exception_rc(const std::exception &ex);
+static void init_err_key(void);
+static void cleanup_err_key(void *errinfo);
+static void clear_err_info(void);
+
+// Check for error
+#define COASTER_CONDITION(cond, err_rc, err_msg) { \
+  if (!(cond)) { coaster_return_error((err_rc), (err_msg)); }}
+
+// TODO: it's bad that this might allocate memory
+#define COASTER_CHECK_MALLOC(ptr) { \
+  if ((ptr) == NULL) { \
+    coaster_return_error(COASTER_ERROR_OOM, "out of memory"); }}
+
+coaster_rc
+coaster_client_start(const char *service_url, size_t service_url_len,
+                    coaster_client **client) COASTER_THROWS_NOTHING {
+  try {
+    *client = new coaster_client(string(service_url, service_url_len));
+    COASTER_CHECK_MALLOC(*client);
+
+    (*client)->loop.start();
+    (*client)->client.start();
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc coaster_client_stop(coaster_client *client)
+                               COASTER_THROWS_NOTHING {
+  try {
+    client->client.stop();
+    client->loop.stop();
+
+    delete client;
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc coaster_settings_create(coaster_settings **settings)
+                                COASTER_THROWS_NOTHING {
+  try {
+    *settings = new Settings();
+    COASTER_CHECK_MALLOC(*settings);
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+static void
+settings_emit(coaster_settings *settings, string &key, string &value);
+
+coaster_rc
+coaster_settings_parse(coaster_settings *settings,
+              const char *str, size_t str_len, char separator)
+                                COASTER_THROWS_NOTHING {
+  COASTER_CONDITION(settings != NULL, COASTER_ERROR_INVALID,
+                    "Null Coaster settings object");
+  COASTER_CONDITION(str != NULL, COASTER_ERROR_INVALID,
+                    "Null Coaster settings string");
+  string key, value; // Storage for current key and value
+
+  bool in_key = true; // Either in key or value
+  bool in_quotes = false;
+  bool in_escape = false;
+
+  for (size_t pos = 0; pos < str_len; pos++) {
+    char c = str[pos];
+    string &curr = in_key ? key : value;
+
+    if (in_escape) {
+      // Current character is escaped
+      curr.push_back(c);
+      in_escape = false;
+
+    } else if (in_quotes) {
+      if (c == '\\') {
+        in_escape = true;
+      } else if (c == '"') {
+        in_quotes = false;
+      } else {
+        curr.push_back(c);
+      }
+    } else {
+      // Not in escape or quotes
+      if (c == '\\') {
+        in_escape = true;
+      } else if (c == '"') {
+        in_quotes = true;
+      } else if (c == '=') {
+        COASTER_CONDITION(in_key, COASTER_ERROR_INVALID,
+                  "'=' not allowed in unquoted Coaster settings value");
+        in_key = false;
+      } else if (c == separator) {
+        COASTER_CONDITION(!in_key, COASTER_ERROR_INVALID,
+                  "',' not allowed in unquoted Coaster settings key");
+
+        settings_emit(settings, key, value);
+
+        in_key = true;
+      } else {
+        curr.push_back(c);
+      }
+    }
+  }
+
+  // Check for invalid state
+  COASTER_CONDITION(!in_escape, COASTER_ERROR_INVALID,
+        "Trailing '\\' escape at end of Coaster settings");
+  COASTER_CONDITION(!in_quotes, COASTER_ERROR_INVALID,
+        "Unclosed '\"' quote at end of Coaster settings");
+  COASTER_CONDITION(!in_key, COASTER_ERROR_INVALID,
+        "Key without value at end of Coaster settings");
+
+  settings_emit(settings, key, value);
+
+  return COASTER_SUCCESS;
+}
+
+
+/*
+ * Helper function to emit completed key/value setting
+ */
+static void
+settings_emit(coaster_settings *settings, string &key, string &value) {
+  if (settings->contains(key)) {
+    string old_value;
+    settings->get(key, old_value);
+    LogWarn << "Overwrote previous Coaster settings value for "
+                "key: \"" << key << "\".  Old value: \"" <<
+                old_value << "\", New value: \"" <<
+                value << "\"." << endl;
+  }
+
+  settings->set(key, value);
+  key.clear();
+  value.clear();
+}
+
+coaster_rc
+coaster_settings_set(coaster_settings *settings,
+          const char *key, size_t key_len,
+          const char *value, size_t value_len) COASTER_THROWS_NOTHING {
+  try {
+    settings->set(key, key_len, value, value_len);
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_settings_get(coaster_settings *settings,
+            const char *key, size_t key_len,
+            const char **value, size_t *value_len) COASTER_THROWS_NOTHING {
+  try {
+    std::map<string, string> &map = settings->getSettings();
+    std::string &str_value = map[string(key, key_len)];
+    *value = str_value.c_str();
+    *value_len = str_value.length();
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_settings_keys(coaster_settings *settings,
+              const char ***keys, size_t **key_lens, int *count)
+                                COASTER_THROWS_NOTHING {
+  try {
+    std::map<string, string> &map = settings->getSettings();
+    *count = map.size();
+
+    // Use malloc so C client code can free
+    *keys = (const char**)malloc(sizeof((*keys)[0]) * (*count));
+    COASTER_CHECK_MALLOC(*keys);
+
+    if (key_lens != NULL) {
+      *key_lens = (size_t *)malloc(sizeof((*key_lens)[0]) * (*count));
+      if (!(*key_lens)) {
+        free(*keys);
+        COASTER_CHECK_MALLOC(*key_lens);
+      }
+    }
+
+    int pos = 0;
+    for(std::map<string, string>::iterator iter = map.begin();
+        iter != map.end(); ++iter) {
+      (*keys)[pos] = iter->first.c_str();
+      if (key_lens != NULL) {
+        (*key_lens)[pos] = iter->first.length();
+      }
+      pos++;
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+void
+coaster_settings_free(coaster_settings *settings)
+                                COASTER_THROWS_NOTHING {
+  // Call destructor directly
+  // Destructor shouldn't throw anything
+  delete settings;
+}
+
+/*
+ * Apply settings to started coaster client.
+ */
+coaster_rc
+coaster_apply_settings(coaster_client *client,
+        coaster_settings *settings, coaster_config_id **config)
+                                  COASTER_THROWS_NOTHING {
+  if (settings == NULL || client == NULL || config == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
+  }
+
+  try {
+    string *configId = new string;
+    *configId = client->client.setOptions(*settings);
+    *config = configId;
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_config_id_free(coaster_config_id *config) COASTER_THROWS_NOTHING {
+  delete config;
+  return COASTER_SUCCESS;
+}
+
+coaster_rc
+coaster_job_create(const char *executable, size_t executable_len,
+                  int argc, const char **argv, const size_t *arg_lens,
+                  const char *job_manager, size_t job_manager_len,
+                  coaster_job **job) COASTER_THROWS_NOTHING {
+  try {
+    assert(executable != NULL);
+    Job *j = new Job(string(executable, executable_len));
+
+    for (int i = 0; i < argc; i++)
+    {
+      assert(argv[i] != NULL);
+      j->addArgument(argv[i], arg_lens[i]);
+    }
+
+    if (job_manager != NULL) {
+      j->setJobManager(job_manager, job_manager_len);
+    }
+
+    *job = j;
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_job_free(coaster_job *job) COASTER_THROWS_NOTHING {
+  // Destructor shouldn't throw anything
+  delete job;
+  return COASTER_SUCCESS;
+}
+
+coaster_rc
+coaster_job_to_string(const coaster_job *job, char **str, size_t *str_len)
+                                   COASTER_THROWS_NOTHING {
+  if (job == NULL || str == NULL || str_len == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid argument");
+  }
+
+  try {
+    string jobStr = job->toString();
+
+    *str = (char*)malloc(jobStr.length() + 1);
+    COASTER_CHECK_MALLOC(*str);
+    memcpy(*str, jobStr.c_str(), jobStr.length() + 1);
+    *str_len = jobStr.length();
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+
+}
+
+coaster_rc
+coaster_job_set_redirects(coaster_job *job,
+      const char *stdin_loc, size_t stdin_loc_len,
+      const char *stdout_loc, size_t stdout_loc_len,
+      const char *stderr_loc, size_t stderr_loc_len)
+                  COASTER_THROWS_NOTHING {
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
+  }
+
+  try {
+    // job expects to get ownership of references, so use new
+    if (stdin_loc != NULL) {
+      job->setStdinLocation(*new string(stdin_loc, stdin_loc_len));
+    }
+
+    if (stdout_loc != NULL) {
+      job->setStdoutLocation(*new string(stdout_loc, stdout_loc_len));
+    }
+
+    if (stderr_loc != NULL) {
+      job->setStderrLocation(*new string(stderr_loc, stderr_loc_len));
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_job_set_directory(coaster_job *job, const char *dir, size_t dir_len)
+                  COASTER_THROWS_NOTHING {
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "");
+  }
+
+  try {
+    if (dir != NULL) {
+      job->setDirectory(*new string(dir, dir_len));
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_job_set_envs(coaster_job *job, int nvars,
+      const char **names, size_t *name_lens,
+      const char **values, size_t *value_lens) COASTER_THROWS_NOTHING {
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
+  }
+
+  try {
+    for (int i = 0; i < nvars; i++)
+    {
+      const char *name = names[i];
+      size_t name_len = name_lens[i];
+      const char *value = values[i];
+      size_t value_len = value_lens[i];
+      COASTER_CONDITION(name != NULL && value != NULL,
+            COASTER_ERROR_INVALID, "Env var name or value was NULL");
+      job->setEnv(name, name_len, value, value_len);
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+/*
+ * Add attributes for the job.  Will overwrite any previous atrributes
+ * if names match.
+ */
+coaster_rc
+coaster_job_set_attrs(coaster_job *job, int nattrs,
+        const char **names, size_t *name_lens,
+        const char **values, size_t *value_lens) COASTER_THROWS_NOTHING {
+
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
+  }
+
+  try {
+    for (int i = 0; i < nattrs; i++)
+    {
+      const char *name = names[i];
+      size_t name_len = name_lens[i];
+      const char *value = values[i];
+      size_t value_len = value_lens[i];
+      COASTER_CONDITION(name != NULL && value != NULL,
+            COASTER_ERROR_INVALID, "Attribute name or value was NULL");
+      job->setAttribute(name, name_len, value, value_len);
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_job_add_cleanups(coaster_job *job, int ncleanups,
+        const char **cleanups, size_t *cleanup_lens)
+        COASTER_THROWS_NOTHING {
+
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
+  }
+
+  try {
+    for (int i = 0; i < ncleanups; i++) {
+      const char *cleanup = cleanups[i];
+      size_t cleanup_len = cleanup_lens[i];
+      COASTER_CONDITION(cleanup != NULL,
+            COASTER_ERROR_INVALID, "Cleanup was NULL");
+      job->addCleanup(cleanup, cleanup_len);
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_job_add_stages(coaster_job *job,
+    int nstageins, coaster_stage_entry *stageins,
+    int nstageouts, coaster_stage_entry *stageouts)
+        COASTER_THROWS_NOTHING {
+
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
+  }
+
+  try {
+    for (int i = 0; i < nstageins; i++) {
+      coaster_stage_entry *s = &stageins[i];
+      job->addStageIn(string(s->src, s->src_len),
+                      string(s->dst, s->dst_len), s->mode);
+    }
+
+    for (int i = 0; i < nstageouts; i++) {
+      coaster_stage_entry *s = &stageouts[i];
+      job->addStageOut(string(s->src, s->src_len),
+                       string(s->dst, s->dst_len), s->mode);
+    }
+
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+
+}
+
+coaster_job_id
+coaster_job_get_id(const coaster_job *job) COASTER_THROWS_NOTHING {
+  // Shouldn't throw anything from accessor method
+  return job->getIdentity();
+}
+
+coaster_rc
+coaster_job_status_code(const coaster_job *job, coaster_job_status *code)
+                                            COASTER_THROWS_NOTHING {
+  const JobStatus *status;
+  if (job == NULL || (status = job->getStatus()) == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID,
+                                "invalid or unsubmitted job");
+  }
+
+  *code = status->getStatusCode();
+  return COASTER_SUCCESS;
+}
+
+coaster_rc
+coaster_job_get_outstreams(const coaster_job *job,
+                const char **stdout_s, size_t *stdout_len,
+                const char **stderr_s, size_t *stderr_len)
+                COASTER_THROWS_NOTHING {
+  if (job == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
+  }
+
+  const string *out = job->getStdout();
+  const string *err = job->getStderr();
+
+  if (out != NULL) {
+    *stderr_s = out->c_str();
+    *stderr_len = out->length();
+  } else {
+    *stderr_s = NULL;
+    *stderr_len = 0;
+  }
+
+  if (err != NULL) {
+    *stderr_s = err->c_str();
+    *stderr_len = err->length();
+  } else {
+    *stderr_s = NULL;
+    *stderr_len = 0;
+  }
+
+  return COASTER_SUCCESS;
+}
+
+coaster_rc
+coaster_submit(coaster_client *client, const coaster_config_id *config,
+               coaster_job *job) COASTER_THROWS_NOTHING {
+  if (client == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid client");
+  }
+  if (config == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid config");
+  }
+
+  try {
+    client->client.submit(*job, *config);
+    return COASTER_SUCCESS;
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+coaster_rc
+coaster_check_jobs(coaster_client *client, bool wait, int maxjobs,
+                   coaster_job **jobs, int *njobs)
+                COASTER_THROWS_NOTHING {
+  if (client == NULL) {
+    return coaster_return_error(COASTER_ERROR_INVALID, "invalid client");
+  }
+
+  try {
+    if (wait) {
+      client->client.waitForAnyJob();
+    }
+
+    int n = client->client.getAndPurgeDoneJobs(maxjobs, jobs);
+
+    *njobs = n;
+    return COASTER_SUCCESS;
+
+  } catch (const CoasterError& err) {
+    return coaster_error_rc(err);
+  } catch (const std::exception& ex) {
+    return exception_rc(ex);
+  }
+}
+
+const char *coaster_rc_string(coaster_rc code)
+{
+  switch (code)
+  {
+    case COASTER_SUCCESS:
+      return "COASTER_SUCCESS";
+    case COASTER_ERROR_OOM:
+      return "COASTER_ERROR_OOM";
+    case COASTER_ERROR_NETWORK:
+      return "COASTER_ERROR_NETWORK";
+    case COASTER_ERROR_UNKNOWN:
+      return "COASTER_ERROR_UNKNOWN";
+    default:
+      return (const char*)0;
+  }
+}
+
+const char *coaster_last_err_info(void) {
+  // Ensure initialized
+  pthread_once(&err_key_init, init_err_key);
+
+  void *val = pthread_getspecific(err_key);
+  if (val == NULL) {
+    return NULL;
+  }
+
+  coaster_err_info *info = static_cast<coaster_err_info *>(val);
+  return info->msg.c_str();
+}
+
+static void init_err_key(void) {
+  pthread_key_create(&err_key, cleanup_err_key);
+}
+
+/*
+ * Called to cleanup error key
+ */
+static void cleanup_err_key(void *errinfo) {
+  delete static_cast<coaster_err_info*>(errinfo);
+}
+
+static void set_err_info(const string& msg) {
+  // Ensure key is initialized
+  pthread_once(&err_key_init, init_err_key);
+
+  void *prev = pthread_getspecific(err_key);
+  if (prev != NULL) {
+    cleanup_err_key(prev);
+  }
+
+  coaster_err_info *err_info = new coaster_err_info(msg);
+  pthread_setspecific(err_key, static_cast<void*>(err_info));
+}
+
+static void clear_err_info(void) {
+  void *prev = pthread_getspecific(err_key);
+  if (prev != NULL) {
+    cleanup_err_key(prev);
+  }
+
+  pthread_setspecific(err_key, NULL);
+}
+
+/*
+ * Helper to set error info when returning error.
+ */
+static coaster_rc coaster_return_error(coaster_rc code,
+                                    const string& msg) {
+  set_err_info(msg);
+  return code;
+}
+
+/*
+ * Set error information and return appropriate code
+ */
+static coaster_rc coaster_error_rc(const CoasterError &err) {
+  const char *msg = err.what();
+  if (msg != NULL) {
+    set_err_info(string(msg));
+  } else {
+    clear_err_info();
+  }
+  // TODO: distinguish different cases?
+  return COASTER_ERROR_UNKNOWN;
+}
+
+static coaster_rc exception_rc(const std::exception &ex) {
+  const char *msg = ex.what();
+  if (msg != NULL) {
+    set_err_info(string(msg));
+  } else {
+    clear_err_info();
+  }
+  // TODO: handle specific types, e.g. bad_alloc
+  return COASTER_ERROR_UNKNOWN;
+}
+
+coaster_rc coaster_set_log_threshold(coaster_log_level threshold) {
+
+  Logger::singleton().setThreshold(threshold);
+
+  return COASTER_SUCCESS;
+}
Index: modules/provider-coaster-c-client/src/coaster.h
===================================================================
--- modules/provider-coaster-c-client/src/coaster.h	(revision 0)
+++ modules/provider-coaster-c-client/src/coaster.h	(revision 4026)
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2014 University of Chicago and Argonne National Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+/*
+ * coaster.h
+ *
+ * Created: Jun 18, 2014
+ *    Author: Tim Armstrong
+ *
+ * Pure C interface for Coaster client.  This aims to expose a subset of the
+ * C++ API's functionality that is sufficient to support all common use
+ * cases for submitting jobs through Coaster services.
+ */
+
+#ifndef COASTER_H__H_
+#define COASTER_H__H_
+
+#ifdef __cplusplus
+#include <string>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+#include <cstddef>
+#else
+#include <stddef.h>
+#endif
+
+#include "coaster-defs.h"
+
+// Opaque pointer types
+typedef struct coaster_client coaster_client;
+
+/*
+  Treat some types as direct pointers to real classes for C++, but opaque
+  pointers to dummy structs for C code to allow typechecking, but prevent
+  manipulation of the rbjects.
+ */
+#ifdef __cplusplus
+namespace Coaster {
+  class Settings;
+  class Job;
+}
+
+typedef class Coaster::Settings coaster_settings;
+typedef std::string coaster_config_id;
+typedef class Coaster::Job coaster_job;
+#else
+// Treat these types as opaque pointer to unimplemented struct for C
+typedef struct coaster_settings_opaque_ coaster_settings;
+typedef struct coaster_config_id_opaque_ coaster_config_id;
+typedef struct coaster_job_opaque_ coaster_job;
+#endif
+
+/*
+ * Return codes for coaster errors
+ * Additional info may be available through coaster_last_err_info()
+ */
+typedef enum {
+  COASTER_SUCCESS,
+  COASTER_ERROR_INVALID,
+  COASTER_ERROR_OOM,
+  COASTER_ERROR_NETWORK,
+  COASTER_ERROR_UNKNOWN,
+} coaster_rc;
+
+/*
+ * Information about a file to be staged
+ */
+typedef struct {
+  const char *src;
+  size_t src_len;
+
+  const char *dst;
+  size_t dst_len;
+
+  coaster_staging_mode mode;
+} coaster_stage_entry;
+
+// Set appropriate macro to specify that we shouldn't throw exceptions
+#ifdef __cplusplus
+#define COASTER_THROWS_NOTHING throw()
+#else
+#define COASTER_THROWS_NOTHING
+#endif
+
+/*
+ * Start a new coaster client.
+ * NOTE: don't support multiple clients per loop with this interface
+ *
+ * service_url[_len]: coaster service URL string with string length
+ * client: output for new client
+ */
+coaster_rc
+coaster_client_start(const char *service_url, size_t service_url_len,
+                    coaster_client **client) COASTER_THROWS_NOTHING;
+
+/*
+ * Stop coaster client and free all memory.
+ *
+ * After calling this the client is invalid and should not be used as
+ * an argument to any more Coaster C API function calls.
+ */
+coaster_rc
+coaster_client_stop(coaster_client *client) COASTER_THROWS_NOTHING;
+
+/*
+ * Create empty settings object
+ * settings: coaster settings object, should be freed with
+             coaster_settings_free
+ */
+coaster_rc
+coaster_settings_create(coaster_settings **settings)
+                    COASTER_THROWS_NOTHING;
+
+/*
+ * Free memory associated with coaster settings
+ */
+void
+coaster_settings_free(coaster_settings *settings)
+                                COASTER_THROWS_NOTHING;
+
+/*
+ * Parse settings from string.
+ *
+ * str[_len]: String with key/value settings and length of string.
+      Settings separated by separator char, key/values separated by equals sign.
+      Backslash escapes the next character.
+      Keys and values can be quoted with ".
+   separator: character to separate keys/values
+ */
+coaster_rc
+coaster_settings_parse(coaster_settings *settings, const char *str,
+             size_t str_len, char separator) COASTER_THROWS_NOTHING;
+/*
+ * Set settings individually.
+ */
+coaster_rc
+coaster_settings_set(coaster_settings *settings,
+            const char *key, size_t key_len,
+            const char *value, size_t value_len) COASTER_THROWS_NOTHING;
+/*
+ * Get settings individually.
+ * value[_len]: set to value of string, null if not present in settings.
+ *      Settings retains ownership of strings: any subsequent
+ *      modifications to settings may invalidate the strings.
+ */
+coaster_rc
+coaster_settings_get(coaster_settings *settings,
+            const char *key, size_t key_len,
+            const char **value, size_t *value_len) COASTER_THROWS_NOTHING;
+
+/*
+ * Enumerate settings.
+ * keys: output array of constant strings.  Array must be freed by
+ *      callee.  Settings retains ownership of strings: any subsequent
+ *      modifications to settings may invalidate the strings.
+ * key_lens: optional output array for string lengths.
+ * count: number of keys in output array
+ */
+coaster_rc
+coaster_settings_keys(coaster_settings *settings,
+                      const char ***keys, size_t **key_lens, int *count)
+                                COASTER_THROWS_NOTHING;
+
+/*
+ * Apply settings to started coaster client.
+ * TODO: currently it isn't safe to free settings until client is shut
+ *       down
+ *
+ * config: set to identifer for this service config, must be freed with
+ *     coaster_free_config_id
+ */
+coaster_rc
+coaster_apply_settings(coaster_client *client,
+        coaster_settings *settings, coaster_config_id **config)
+                                  COASTER_THROWS_NOTHING;
+
+coaster_rc
+coaster_config_id_free(coaster_config_id *config) COASTER_THROWS_NOTHING;
+
+/*
+ * Create a new coaster job for later submission.
+ * Some standard arguments can be specified now, or left as NULL to be
+ * initialized later.
+ *
+ * executable: must be provided, name of executable
+ * argc/argv: command line arguments
+ * job_manager: Name of Coaster job manager to use (can be NULL)
+ * job: output, filled with pointer to new job
+ */
+coaster_rc
+coaster_job_create(const char *executable, size_t executable_len,
+                  int argc, const char **argv, const size_t *arg_lens,
+                  const char *job_manager, size_t job_manager_len,
+                  coaster_job **job) COASTER_THROWS_NOTHING;
+
+/*
+ * Free a coaster job
+ */
+coaster_rc
+coaster_job_free(coaster_job *job) COASTER_THROWS_NOTHING;
+
+/*
+ * Create a human readable string describing job.
+ * str: output for dynamically allocated string, to be freed by caller
+ */
+coaster_rc
+coaster_job_to_string(const coaster_job *job, char **str, size_t *str_len)
+                                  COASTER_THROWS_NOTHING;
+
+/*
+ * Set input and output stream redirections.
+ * If set to NULL, don't modify.
+ */
+coaster_rc
+coaster_job_set_redirects(coaster_job *job,
+      const char *stdin_loc, size_t stdin_loc_len,
+      const char *stdout_loc, size_t stdout_loc_len,
+      const char *stderr_loc, size_t stderr_loc_len)
+                  COASTER_THROWS_NOTHING;
+
+/*
+ * Set job directory.
+ * If dir is NULL, no effect
+ */
+coaster_rc
+coaster_job_set_directory(coaster_job *job, const char *dir, size_t dir_len)
+                  COASTER_THROWS_NOTHING;
+
+/*
+ * Add environment variables for the job.  Will overwrite any
+ * previous values if names match.
+ * name and value strings should not be NULL.
+ */
+coaster_rc
+coaster_job_set_envs(coaster_job *job, int nvars,
+        const char **names, size_t *name_lens,
+        const char **values, size_t *value_lens) COASTER_THROWS_NOTHING;
+
+/*
+ * Add attributes for the job.  Will overwrite any previous atrributes
+ * if names match.
+ * name and value strings should not be NULL.
+ */
+coaster_rc
+coaster_job_set_attrs(coaster_job *job, int nattrs,
+        const char **names, size_t *name_lens,
+        const char **values, size_t *value_lens) COASTER_THROWS_NOTHING;
+
+/*
+ * Add cleanups for job.
+ */
+coaster_rc
+coaster_job_add_cleanups(coaster_job *job, int ncleanups,
+        const char **cleanups, size_t *cleanup_lens)
+        COASTER_THROWS_NOTHING;
+
+/*
+ * Add staging set entries for job
+ */
+coaster_rc
+coaster_job_add_stages(coaster_job *job,
+    int nstageins, coaster_stage_entry *stageins,
+    int nstageouts, coaster_stage_entry *stageouts)
+        COASTER_THROWS_NOTHING;
+
+/*
+ * Get local job ID.  The job ID is a locally unique identifier for
+ * a coaster job that is assigned when the job is created.
+ */
+coaster_job_id 
+coaster_job_get_id(const coaster_job *job) COASTER_THROWS_NOTHING;
+
+/*
+ * Get status of a submitted job.
+ * Return COASTER_ERROR_INVALID if job is invalid or has no status.
+ */
+coaster_rc
+coaster_job_status_code(const coaster_job *job, coaster_job_status *code)
+                COASTER_THROWS_NOTHING;
+
+/*
+ * Get stdin/out of completed job.
+ * Pointers set to NULL and lengths to 0 if not available.  Strings
+ * are owned by job: will become invalid if job is freed.
+ */
+coaster_rc
+coaster_job_get_outstreams(const coaster_job *job,
+                const char **stdout_s, size_t *stdout_len,
+                const char **stderr_s, size_t *stderr_len)
+                COASTER_THROWS_NOTHING;
+
+/*
+ * Submit a coaster job through a coaster client.
+ * A job can only be submitted once!
+ * Ownership of the job is shared between the caller and
+ * the client until the job has completed, or the client
+ * shuts down.
+ *
+ * config: required, must be non-null
+ */
+coaster_rc
+coaster_submit(coaster_client *client, const coaster_config_id *config,
+               coaster_job *job) COASTER_THROWS_NOTHING;
+
+/*
+ * Check for completion of jobs.
+ *
+ * wait: if true, don't return until at least one job completes
+ * maxjobs: maximum number of jobs to return
+ * jobs: output array large enough to hold maxjobs
+ * njobs: output for number of jobs returned in jobs
+ */
+coaster_rc
+coaster_check_jobs(coaster_client *client, bool wait, int maxjobs,
+                   coaster_job **jobs, int *njobs)
+                COASTER_THROWS_NOTHING;
+
+/*
+ * Get name of return code.  Returns NULL if invalid code.
+ */
+const char *coaster_rc_string(coaster_rc code);
+
+/*
+ * Get additional information about last returned error in current
+ * thread.
+ * returns: error message, NULL if no information available.  The
+ *          returned string is valid until the next call by this thread
+ *          to a coaster API function.
+ */
+const char *coaster_last_err_info(void);
+
+coaster_rc coaster_set_log_threshold(coaster_log_level threshold);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif // COASTER_H__H_
Index: modules/provider-coaster-c-client/src/Job.h
===================================================================
--- modules/provider-coaster-c-client/src/Job.h	(revision 4025)
+++ modules/provider-coaster-c-client/src/Job.h	(working copy)
@@ -19,7 +19,7 @@
 namespace Coaster {
 
 /*
-  Job represents a single Job that is to be submitted to coasters.
+  Job represents a single Job that is to be submitted to coaster service.
   The Job object is created and has its parameters set before submission.
   Once submitted, its status is updated to reflect its progress.
  */
Index: modules/provider-coaster-c-client/src/coasters.cpp
===================================================================
--- modules/provider-coaster-c-client/src/coasters.cpp	(revision 4025)
+++ modules/provider-coaster-c-client/src/coasters.cpp	(working copy)
@@ -1,752 +0,0 @@
-/*
- * Copyright 2014 University of Chicago and Argonne National Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-/*
- * Implementation of pure C functions.
- *
- * Created: Jun 18, 2014
- *    Author: Tim Armstrong
- */
-
-#include "coasters.h"
-
-#include <cassert>
-#include <cstdlib>
-#include <cstring>
-#include <pthread.h>
-
-#include "CoasterClient.h"
-#include "CoasterError.h"
-#include "CoasterLoop.h"
-#include "Settings.h"
-
-using namespace Coaster;
-
-using std::malloc;
-using std::free;
-
-using std::string;
-using std::memcpy;
-
-/*
-  Struct just wraps the objects
- */
-struct coaster_client {
-  CoasterLoop loop;
-  CoasterClient client;
-
-  /*
-    Constructor: initialize loop then client
-   */
-  coaster_client(string serviceURL) :
-        loop(), client(serviceURL, loop) { }
-};
-
-struct coaster_err_info {
-  string msg;
-
-  coaster_err_info(const string _msg): msg(_msg) {}
-};
-
-static pthread_key_t err_key;
-static pthread_once_t err_key_init = PTHREAD_ONCE_INIT;
-
-static coaster_rc coaster_return_error(coaster_rc code,
-                                    const string &msg);
-static coaster_rc coaster_error_rc(const CoasterError &err);
-static coaster_rc exception_rc(const std::exception &ex);
-static void init_err_key(void);
-static void cleanup_err_key(void *errinfo);
-static void clear_err_info(void);
-
-// Check for error
-#define COASTER_CONDITION(cond, err_rc, err_msg) { \
-  if (!(cond)) { coaster_return_error((err_rc), (err_msg)); }}
-
-// TODO: it's bad that this might allocate memory
-#define COASTER_CHECK_MALLOC(ptr) { \
-  if ((ptr) == NULL) { \
-    coaster_return_error(COASTER_ERROR_OOM, "out of memory"); }}
-
-coaster_rc
-coaster_client_start(const char *service_url, size_t service_url_len,
-                    coaster_client **client) COASTER_THROWS_NOTHING {
-  try {
-    *client = new coaster_client(string(service_url, service_url_len));
-    COASTER_CHECK_MALLOC(*client);
-
-    (*client)->loop.start();
-    (*client)->client.start();
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc coaster_client_stop(coaster_client *client)
-                               COASTER_THROWS_NOTHING {
-  try {
-    client->client.stop();
-    client->loop.stop();
-
-    delete client;
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc coaster_settings_create(coaster_settings **settings)
-                                COASTER_THROWS_NOTHING {
-  try {
-    *settings = new Settings();
-    COASTER_CHECK_MALLOC(*settings);
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-static void
-settings_emit(coaster_settings *settings, string &key, string &value);
-
-coaster_rc
-coaster_settings_parse(coaster_settings *settings,
-              const char *str, size_t str_len, char separator)
-                                COASTER_THROWS_NOTHING {
-  COASTER_CONDITION(settings != NULL, COASTER_ERROR_INVALID,
-                    "Null Coaster settings object");
-  COASTER_CONDITION(str != NULL, COASTER_ERROR_INVALID,
-                    "Null Coaster settings string");
-  string key, value; // Storage for current key and value
-
-  bool in_key = true; // Either in key or value
-  bool in_quotes = false;
-  bool in_escape = false;
-
-  for (size_t pos = 0; pos < str_len; pos++) {
-    char c = str[pos];
-    string &curr = in_key ? key : value;
-
-    if (in_escape) {
-      // Current character is escaped
-      curr.push_back(c);
-      in_escape = false;
-
-    } else if (in_quotes) {
-      if (c == '\\') {
-        in_escape = true;
-      } else if (c == '"') {
-        in_quotes = false;
-      } else {
-        curr.push_back(c);
-      }
-    } else {
-      // Not in escape or quotes
-      if (c == '\\') {
-        in_escape = true;
-      } else if (c == '"') {
-        in_quotes = true;
-      } else if (c == '=') {
-        COASTER_CONDITION(in_key, COASTER_ERROR_INVALID,
-                  "'=' not allowed in unquoted Coaster settings value");
-        in_key = false;
-      } else if (c == separator) {
-        COASTER_CONDITION(!in_key, COASTER_ERROR_INVALID,
-                  "',' not allowed in unquoted Coaster settings key");
-
-        settings_emit(settings, key, value);
-
-        in_key = true;
-      } else {
-        curr.push_back(c);
-      }
-    }
-  }
-
-  // Check for invalid state
-  COASTER_CONDITION(!in_escape, COASTER_ERROR_INVALID,
-        "Trailing '\\' escape at end of Coaster settings");
-  COASTER_CONDITION(!in_quotes, COASTER_ERROR_INVALID,
-        "Unclosed '\"' quote at end of Coaster settings");
-  COASTER_CONDITION(!in_key, COASTER_ERROR_INVALID,
-        "Key without value at end of Coaster settings");
-
-  settings_emit(settings, key, value);
-
-  return COASTER_SUCCESS;
-}
-
-
-/*
- * Helper function to emit completed key/value setting
- */
-static void
-settings_emit(coaster_settings *settings, string &key, string &value) {
-  if (settings->contains(key)) {
-    string old_value;
-    settings->get(key, old_value);
-    LogWarn << "Overwrote previous Coaster settings value for "
-                "key: \"" << key << "\".  Old value: \"" <<
-                old_value << "\", New value: \"" <<
-                value << "\"." << endl;
-  }
-
-  settings->set(key, value);
-  key.clear();
-  value.clear();
-}
-
-coaster_rc
-coaster_settings_set(coaster_settings *settings,
-          const char *key, size_t key_len,
-          const char *value, size_t value_len) COASTER_THROWS_NOTHING {
-  try {
-    settings->set(key, key_len, value, value_len);
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_settings_get(coaster_settings *settings,
-            const char *key, size_t key_len,
-            const char **value, size_t *value_len) COASTER_THROWS_NOTHING {
-  try {
-    std::map<string, string> &map = settings->getSettings();
-    std::string &str_value = map[string(key, key_len)];
-    *value = str_value.c_str();
-    *value_len = str_value.length();
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_settings_keys(coaster_settings *settings,
-              const char ***keys, size_t **key_lens, int *count)
-                                COASTER_THROWS_NOTHING {
-  try {
-    std::map<string, string> &map = settings->getSettings();
-    *count = map.size();
-
-    // Use malloc so C client code can free
-    *keys = (const char**)malloc(sizeof((*keys)[0]) * (*count));
-    COASTER_CHECK_MALLOC(*keys);
-
-    if (key_lens != NULL) {
-      *key_lens = (size_t *)malloc(sizeof((*key_lens)[0]) * (*count));
-      if (!(*key_lens)) {
-        free(*keys);
-        COASTER_CHECK_MALLOC(*key_lens);
-      }
-    }
-
-    int pos = 0;
-    for(std::map<string, string>::iterator iter = map.begin();
-        iter != map.end(); ++iter) {
-      (*keys)[pos] = iter->first.c_str();
-      if (key_lens != NULL) {
-        (*key_lens)[pos] = iter->first.length();
-      }
-      pos++;
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-void
-coaster_settings_free(coaster_settings *settings)
-                                COASTER_THROWS_NOTHING {
-  // Call destructor directly
-  // Destructor shouldn't throw anything
-  delete settings;
-}
-
-/*
- * Apply settings to started coasters client.
- */
-coaster_rc
-coaster_apply_settings(coaster_client *client,
-        coaster_settings *settings, coaster_config_id **config)
-                                  COASTER_THROWS_NOTHING {
-  if (settings == NULL || client == NULL || config == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
-  }
-
-  try {
-    string *configId = new string;
-    *configId = client->client.setOptions(*settings);
-    *config = configId;
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_config_id_free(coaster_config_id *config) COASTER_THROWS_NOTHING {
-  delete config;
-  return COASTER_SUCCESS;
-}
-
-coaster_rc
-coaster_job_create(const char *executable, size_t executable_len,
-                  int argc, const char **argv, const size_t *arg_lens,
-                  const char *job_manager, size_t job_manager_len,
-                  coaster_job **job) COASTER_THROWS_NOTHING {
-  try {
-    assert(executable != NULL);
-    Job *j = new Job(string(executable, executable_len));
-
-    for (int i = 0; i < argc; i++)
-    {
-      assert(argv[i] != NULL);
-      j->addArgument(argv[i], arg_lens[i]);
-    }
-
-    if (job_manager != NULL) {
-      j->setJobManager(job_manager, job_manager_len);
-    }
-
-    *job = j;
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_job_free(coaster_job *job) COASTER_THROWS_NOTHING {
-  // Destructor shouldn't throw anything
-  delete job;
-  return COASTER_SUCCESS;
-}
-
-coaster_rc
-coaster_job_to_string(const coaster_job *job, char **str, size_t *str_len)
-                                   COASTER_THROWS_NOTHING {
-  if (job == NULL || str == NULL || str_len == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid argument");
-  }
-
-  try {
-    string jobStr = job->toString();
-
-    *str = (char*)malloc(jobStr.length() + 1);
-    COASTER_CHECK_MALLOC(*str);
-    memcpy(*str, jobStr.c_str(), jobStr.length() + 1);
-    *str_len = jobStr.length();
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-
-}
-
-coaster_rc
-coaster_job_set_redirects(coaster_job *job,
-      const char *stdin_loc, size_t stdin_loc_len,
-      const char *stdout_loc, size_t stdout_loc_len,
-      const char *stderr_loc, size_t stderr_loc_len)
-                  COASTER_THROWS_NOTHING {
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
-  }
-
-  try {
-    // job expects to get ownership of references, so use new
-    if (stdin_loc != NULL) {
-      job->setStdinLocation(*new string(stdin_loc, stdin_loc_len));
-    }
-
-    if (stdout_loc != NULL) {
-      job->setStdoutLocation(*new string(stdout_loc, stdout_loc_len));
-    }
-
-    if (stderr_loc != NULL) {
-      job->setStderrLocation(*new string(stderr_loc, stderr_loc_len));
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_job_set_directory(coaster_job *job, const char *dir, size_t dir_len)
-                  COASTER_THROWS_NOTHING {
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "");
-  }
-
-  try {
-    if (dir != NULL) {
-      job->setDirectory(*new string(dir, dir_len));
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_job_set_envs(coaster_job *job, int nvars,
-      const char **names, size_t *name_lens,
-      const char **values, size_t *value_lens) COASTER_THROWS_NOTHING {
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid arg");
-  }
-
-  try {
-    for (int i = 0; i < nvars; i++)
-    {
-      const char *name = names[i];
-      size_t name_len = name_lens[i];
-      const char *value = values[i];
-      size_t value_len = value_lens[i];
-      COASTER_CONDITION(name != NULL && value != NULL,
-            COASTER_ERROR_INVALID, "Env var name or value was NULL");
-      job->setEnv(name, name_len, value, value_len);
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-/*
- * Add attributes for the job.  Will overwrite any previous atrributes
- * if names match.
- */
-coaster_rc
-coaster_job_set_attrs(coaster_job *job, int nattrs,
-        const char **names, size_t *name_lens,
-        const char **values, size_t *value_lens) COASTER_THROWS_NOTHING {
-
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
-  }
-
-  try {
-    for (int i = 0; i < nattrs; i++)
-    {
-      const char *name = names[i];
-      size_t name_len = name_lens[i];
-      const char *value = values[i];
-      size_t value_len = value_lens[i];
-      COASTER_CONDITION(name != NULL && value != NULL,
-            COASTER_ERROR_INVALID, "Attribute name or value was NULL");
-      job->setAttribute(name, name_len, value, value_len);
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_job_add_cleanups(coaster_job *job, int ncleanups,
-        const char **cleanups, size_t *cleanup_lens)
-        COASTER_THROWS_NOTHING {
-
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
-  }
-
-  try {
-    for (int i = 0; i < ncleanups; i++) {
-      const char *cleanup = cleanups[i];
-      size_t cleanup_len = cleanup_lens[i];
-      COASTER_CONDITION(cleanup != NULL,
-            COASTER_ERROR_INVALID, "Cleanup was NULL");
-      job->addCleanup(cleanup, cleanup_len);
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_job_add_stages(coaster_job *job,
-    int nstageins, coaster_stage_entry *stageins,
-    int nstageouts, coaster_stage_entry *stageouts)
-        COASTER_THROWS_NOTHING {
-
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
-  }
-
-  try {
-    for (int i = 0; i < nstageins; i++) {
-      coaster_stage_entry *s = &stageins[i];
-      job->addStageIn(string(s->src, s->src_len),
-                      string(s->dst, s->dst_len), s->mode);
-    }
-
-    for (int i = 0; i < nstageouts; i++) {
-      coaster_stage_entry *s = &stageouts[i];
-      job->addStageOut(string(s->src, s->src_len),
-                       string(s->dst, s->dst_len), s->mode);
-    }
-
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-
-}
-
-coaster_job_id
-coaster_job_get_id(const coaster_job *job) COASTER_THROWS_NOTHING {
-  // Shouldn't throw anything from accessor method
-  return job->getIdentity();
-}
-
-coaster_rc
-coaster_job_status_code(const coaster_job *job, coaster_job_status *code)
-                                            COASTER_THROWS_NOTHING {
-  const JobStatus *status;
-  if (job == NULL || (status = job->getStatus()) == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID,
-                                "invalid or unsubmitted job");
-  }
-
-  *code = status->getStatusCode();
-  return COASTER_SUCCESS;
-}
-
-coaster_rc
-coaster_job_get_outstreams(const coaster_job *job,
-                const char **stdout_s, size_t *stdout_len,
-                const char **stderr_s, size_t *stderr_len)
-                COASTER_THROWS_NOTHING {
-  if (job == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid job");
-  }
-
-  const string *out = job->getStdout();
-  const string *err = job->getStderr();
-
-  if (out != NULL) {
-    *stderr_s = out->c_str();
-    *stderr_len = out->length();
-  } else {
-    *stderr_s = NULL;
-    *stderr_len = 0;
-  }
-
-  if (err != NULL) {
-    *stderr_s = err->c_str();
-    *stderr_len = err->length();
-  } else {
-    *stderr_s = NULL;
-    *stderr_len = 0;
-  }
-
-  return COASTER_SUCCESS;
-}
-
-coaster_rc
-coaster_submit(coaster_client *client, const coaster_config_id *config,
-               coaster_job *job) COASTER_THROWS_NOTHING {
-  if (client == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid client");
-  }
-  if (config == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid config");
-  }
-
-  try {
-    client->client.submit(*job, *config);
-    return COASTER_SUCCESS;
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-coaster_rc
-coaster_check_jobs(coaster_client *client, bool wait, int maxjobs,
-                   coaster_job **jobs, int *njobs)
-                COASTER_THROWS_NOTHING {
-  if (client == NULL) {
-    return coaster_return_error(COASTER_ERROR_INVALID, "invalid client");
-  }
-
-  try {
-    if (wait) {
-      client->client.waitForAnyJob();
-    }
-
-    int n = client->client.getAndPurgeDoneJobs(maxjobs, jobs);
-
-    *njobs = n;
-    return COASTER_SUCCESS;
-
-  } catch (const CoasterError& err) {
-    return coaster_error_rc(err);
-  } catch (const std::exception& ex) {
-    return exception_rc(ex);
-  }
-}
-
-const char *coaster_rc_string(coaster_rc code)
-{
-  switch (code)
-  {
-    case COASTER_SUCCESS:
-      return "COASTER_SUCCESS";
-    case COASTER_ERROR_OOM:
-      return "COASTER_ERROR_OOM";
-    case COASTER_ERROR_NETWORK:
-      return "COASTER_ERROR_NETWORK";
-    case COASTER_ERROR_UNKNOWN:
-      return "COASTER_ERROR_UNKNOWN";
-    default:
-      return (const char*)0;
-  }
-}
-
-const char *coaster_last_err_info(void) {
-  // Ensure initialized
-  pthread_once(&err_key_init, init_err_key);
-
-  void *val = pthread_getspecific(err_key);
-  if (val == NULL) {
-    return NULL;
-  }
-
-  coaster_err_info *info = static_cast<coaster_err_info *>(val);
-  return info->msg.c_str();
-}
-
-static void init_err_key(void) {
-  pthread_key_create(&err_key, cleanup_err_key);
-}
-
-/*
- * Called to cleanup error key
- */
-static void cleanup_err_key(void *errinfo) {
-  delete static_cast<coaster_err_info*>(errinfo);
-}
-
-static void set_err_info(const string& msg) {
-  // Ensure key is initialized
-  pthread_once(&err_key_init, init_err_key);
-
-  void *prev = pthread_getspecific(err_key);
-  if (prev != NULL) {
-    cleanup_err_key(prev);
-  }
-
-  coaster_err_info *err_info = new coaster_err_info(msg);
-  pthread_setspecific(err_key, static_cast<void*>(err_info));
-}
-
-static void clear_err_info(void) {
-  void *prev = pthread_getspecific(err_key);
-  if (prev != NULL) {
-    cleanup_err_key(prev);
-  }
-
-  pthread_setspecific(err_key, NULL);
-}
-
-/*
- * Helper to set error info when returning error.
- */
-static coaster_rc coaster_return_error(coaster_rc code,
-                                    const string& msg) {
-  set_err_info(msg);
-  return code;
-}
-
-/*
- * Set error information and return appropriate code
- */
-static coaster_rc coaster_error_rc(const CoasterError &err) {
-  const char *msg = err.what();
-  if (msg != NULL) {
-    set_err_info(string(msg));
-  } else {
-    clear_err_info();
-  }
-  // TODO: distinguish different cases?
-  return COASTER_ERROR_UNKNOWN;
-}
-
-static coaster_rc exception_rc(const std::exception &ex) {
-  const char *msg = ex.what();
-  if (msg != NULL) {
-    set_err_info(string(msg));
-  } else {
-    clear_err_info();
-  }
-  // TODO: handle specific types, e.g. bad_alloc
-  return COASTER_ERROR_UNKNOWN;
-}
-
-coaster_rc coaster_set_log_threshold(coaster_log_level threshold) {
-
-  Logger::singleton().setThreshold(threshold);
-
-  return COASTER_SUCCESS;
-}
Index: modules/provider-coaster-c-client/src/Makefile.am
===================================================================
--- modules/provider-coaster-c-client/src/Makefile.am	(revision 4025)
+++ modules/provider-coaster-c-client/src/Makefile.am	(working copy)
@@ -22,7 +22,7 @@
 
 libcoasterclient_la_SOURCES = \
 	$(SWIG_SRC) \
-        coasters.cpp coasters.h coaster-defs.h \
+        coaster.cpp coaster.h coaster-defs.h \
 	Lock.h Lock.cpp \
 	ConditionVariable.h ConditionVariable.cpp \
 	CommandCallback.h \
Index: modules/provider-coaster-c-client/src/coasters.h
===================================================================
--- modules/provider-coaster-c-client/src/coasters.h	(revision 4025)
+++ modules/provider-coaster-c-client/src/coasters.h	(working copy)
@@ -1,355 +0,0 @@
-/*
- * Copyright 2014 University of Chicago and Argonne National Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-/*
- * coasters.h
- *
- * Created: Jun 18, 2014
- *    Author: Tim Armstrong
- *
- * Pure C interface for Coasters.  This aims to expose a subset of the
- * C++ API's functionality that is sufficient to support all common use
- * cases for submitting jobs through Coasters.
- */
-
-#ifndef COASTERS_H_
-#define COASTERS_H_
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef __cplusplus
-#include <cstddef>
-#else
-#include <stddef.h>
-#endif
-
-#include "coaster-defs.h"
-
-// Opaque pointer types
-typedef struct coaster_client coaster_client;
-
-/*
-  Treat some types as direct pointers to real classes for C++, but opaque
-  pointers to dummy structs for C code to allow typechecking, but prevent
-  manipulation of the rbjects.
- */
-#ifdef __cplusplus
-namespace Coaster {
-  class Settings;
-  class Job;
-}
-
-typedef class Coaster::Settings coaster_settings;
-typedef std::string coaster_config_id;
-typedef class Coaster::Job coaster_job;
-#else
-// Treat these types as opaque pointer to unimplemented struct for C
-typedef struct coaster_settings_opaque_ coaster_settings;
-typedef struct coaster_config_id_opaque_ coaster_config_id;
-typedef struct coaster_job_opaque_ coaster_job;
-#endif
-
-/*
- * Return codes for coaster errors
- * Additional info may be available through coaster_last_err_info()
- */
-typedef enum {
-  COASTER_SUCCESS,
-  COASTER_ERROR_INVALID,
-  COASTER_ERROR_OOM,
-  COASTER_ERROR_NETWORK,
-  COASTER_ERROR_UNKNOWN,
-} coaster_rc;
-
-/*
- * Information about a file to be staged
- */
-typedef struct {
-  const char *src;
-  size_t src_len;
-
-  const char *dst;
-  size_t dst_len;
-
-  coaster_staging_mode mode;
-} coaster_stage_entry;
-
-// Set appropriate macro to specify that we shouldn't throw exceptions
-#ifdef __cplusplus
-#define COASTER_THROWS_NOTHING throw()
-#else
-#define COASTER_THROWS_NOTHING
-#endif
-
-/*
- * Start a new coasters client.
- * NOTE: don't support multiple clients per loop with this interface
- *
- * service_url[_len]: coasters service URL string with string length
- * client: output for new client
- */
-coaster_rc
-coaster_client_start(const char *service_url, size_t service_url_len,
-                    coaster_client **client) COASTER_THROWS_NOTHING;
-
-/*
- * Stop coasters client and free all memory.
- *
- * After calling this the client is invalid and should not be used as
- * an argument to any more Coaster C API function calls.
- */
-coaster_rc
-coaster_client_stop(coaster_client *client) COASTER_THROWS_NOTHING;
-
-/*
- * Create empty settings object
- * settings: coaster settings object, should be freed with
-             coaster_settings_free
- */
-coaster_rc
-coaster_settings_create(coaster_settings **settings)
-                    COASTER_THROWS_NOTHING;
-
-/*
- * Free memory associated with coasters settings
- */
-void
-coaster_settings_free(coaster_settings *settings)
-                                COASTER_THROWS_NOTHING;
-
-/*
- * Parse settings from string.
- *
- * str[_len]: String with key/value settings and length of string.
-      Settings separated by separator char, key/values separated by equals sign.
-      Backslash escapes the next character.
-      Keys and values can be quoted with ".
-   separator: character to separate keys/values
- */
-coaster_rc
-coaster_settings_parse(coaster_settings *settings, const char *str,
-             size_t str_len, char separator) COASTER_THROWS_NOTHING;
-/*
- * Set settings individually.
- */
-coaster_rc
-coaster_settings_set(coaster_settings *settings,
-            const char *key, size_t key_len,
-            const char *value, size_t value_len) COASTER_THROWS_NOTHING;
-/*
- * Get settings individually.
- * value[_len]: set to value of string, null if not present in settings.
- *      Settings retains ownership of strings: any subsequent
- *      modifications to settings may invalidate the strings.
- */
-coaster_rc
-coaster_settings_get(coaster_settings *settings,
-            const char *key, size_t key_len,
-            const char **value, size_t *value_len) COASTER_THROWS_NOTHING;
-
-/*
- * Enumerate settings.
- * keys: output array of constant strings.  Array must be freed by
- *      callee.  Settings retains ownership of strings: any subsequent
- *      modifications to settings may invalidate the strings.
- * key_lens: optional output array for string lengths.
- * count: number of keys in output array
- */
-coaster_rc
-coaster_settings_keys(coaster_settings *settings,
-                      const char ***keys, size_t **key_lens, int *count)
-                                COASTER_THROWS_NOTHING;
-
-/*
- * Apply settings to started coasters client.
- * TODO: currently it isn't safe to free settings until client is shut
- *       down
- *
- * config: set to identifer for this service config, must be freed with
- *     coaster_free_config_id
- */
-coaster_rc
-coaster_apply_settings(coaster_client *client,
-        coaster_settings *settings, coaster_config_id **config)
-                                  COASTER_THROWS_NOTHING;
-
-coaster_rc
-coaster_config_id_free(coaster_config_id *config) COASTER_THROWS_NOTHING;
-
-/*
- * Create a new coasters job for later submission.
- * Some standard arguments can be specified now, or left as NULL to be
- * initialized later.
- *
- * executable: must be provided, name of executable
- * argc/argv: command line arguments
- * job_manager: Name of Coasters job manager to use (can be NULL)
- * job: output, filled with pointer to new job
- */
-coaster_rc
-coaster_job_create(const char *executable, size_t executable_len,
-                  int argc, const char **argv, const size_t *arg_lens,
-                  const char *job_manager, size_t job_manager_len,
-                  coaster_job **job) COASTER_THROWS_NOTHING;
-
-/*
- * Free a coasters job
- */
-coaster_rc
-coaster_job_free(coaster_job *job) COASTER_THROWS_NOTHING;
-
-/*
- * Create a human readable string describing job.
- * str: output for dynamically allocated string, to be freed by caller
- */
-coaster_rc
-coaster_job_to_string(const coaster_job *job, char **str, size_t *str_len)
-                                  COASTER_THROWS_NOTHING;
-
-/*
- * Set input and output stream redirections.
- * If set to NULL, don't modify.
- */
-coaster_rc
-coaster_job_set_redirects(coaster_job *job,
-      const char *stdin_loc, size_t stdin_loc_len,
-      const char *stdout_loc, size_t stdout_loc_len,
-      const char *stderr_loc, size_t stderr_loc_len)
-                  COASTER_THROWS_NOTHING;
-
-/*
- * Set job directory.
- * If dir is NULL, no effect
- */
-coaster_rc
-coaster_job_set_directory(coaster_job *job, const char *dir, size_t dir_len)
-                  COASTER_THROWS_NOTHING;
-
-/*
- * Add environment variables for the job.  Will overwrite any
- * previous values if names match.
- * name and value strings should not be NULL.
- */
-coaster_rc
-coaster_job_set_envs(coaster_job *job, int nvars,
-        const char **names, size_t *name_lens,
-        const char **values, size_t *value_lens) COASTER_THROWS_NOTHING;
-
-/*
- * Add attributes for the job.  Will overwrite any previous atrributes
- * if names match.
- * name and value strings should not be NULL.
- */
-coaster_rc
-coaster_job_set_attrs(coaster_job *job, int nattrs,
-        const char **names, size_t *name_lens,
-        const char **values, size_t *value_lens) COASTER_THROWS_NOTHING;
-
-/*
- * Add cleanups for job.
- */
-coaster_rc
-coaster_job_add_cleanups(coaster_job *job, int ncleanups,
-        const char **cleanups, size_t *cleanup_lens)
-        COASTER_THROWS_NOTHING;
-
-/*
- * Add staging set entries for job
- */
-coaster_rc
-coaster_job_add_stages(coaster_job *job,
-    int nstageins, coaster_stage_entry *stageins,
-    int nstageouts, coaster_stage_entry *stageouts)
-        COASTER_THROWS_NOTHING;
-
-/*
- * Get local job ID.  The job ID is a locally unique identifier for
- * a coasters job that is assigned when the job is created.
- */
-coaster_job_id 
-coaster_job_get_id(const coaster_job *job) COASTER_THROWS_NOTHING;
-
-/*
- * Get status of a submitted job.
- * Return COASTER_ERROR_INVALID if job is invalid or has no status.
- */
-coaster_rc
-coaster_job_status_code(const coaster_job *job, coaster_job_status *code)
-                COASTER_THROWS_NOTHING;
-
-/*
- * Get stdin/out of completed job.
- * Pointers set to NULL and lengths to 0 if not available.  Strings
- * are owned by job: will become invalid if job is freed.
- */
-coaster_rc
-coaster_job_get_outstreams(const coaster_job *job,
-                const char **stdout_s, size_t *stdout_len,
-                const char **stderr_s, size_t *stderr_len)
-                COASTER_THROWS_NOTHING;
-
-/*
- * Submit a coasters job through a coasters client.
- * A job can only be submitted once!
- * Ownership of the job is shared between the caller and
- * the client until the job has completed, or the client
- * shuts down.
- *
- * config: required, must be non-null
- */
-coaster_rc
-coaster_submit(coaster_client *client, const coaster_config_id *config,
-               coaster_job *job) COASTER_THROWS_NOTHING;
-
-/*
- * Check for completion of jobs.
- *
- * wait: if true, don't return until at least one job completes
- * maxjobs: maximum number of jobs to return
- * jobs: output array large enough to hold maxjobs
- * njobs: output for number of jobs returned in jobs
- */
-coaster_rc
-coaster_check_jobs(coaster_client *client, bool wait, int maxjobs,
-                   coaster_job **jobs, int *njobs)
-                COASTER_THROWS_NOTHING;
-
-/*
- * Get name of return code.  Returns NULL if invalid code.
- */
-const char *coaster_rc_string(coaster_rc code);
-
-/*
- * Get additional information about last returned error in current
- * thread.
- * returns: error message, NULL if no information available.  The
- *          returned string is valid until the next call by this thread
- *          to a coasters API function.
- */
-const char *coaster_last_err_info(void);
-
-coaster_rc coaster_set_log_threshold(coaster_log_level threshold);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-#endif // COASTERS_H_
Index: modules/provider-coaster-c-client/Makefile.am
===================================================================
--- modules/provider-coaster-c-client/Makefile.am	(revision 4025)
+++ modules/provider-coaster-c-client/Makefile.am	(working copy)
@@ -2,7 +2,7 @@
 SUBDIRS = src 
 EXTRA_DIST = autogen.sh
 LIBS = -pthread $(LIBS)
-include_HEADERS = src/coasters.h src/coaster-defs.h \
+include_HEADERS = src/coaster.h src/coaster-defs.h \
             src/Buffer.h src/ChannelCallback.h \
             src/ChannelConfigurationCommand.h src/ClientHandlerFactory.h \
             src/CoasterChannel.h src/CoasterClient.h \



More information about the Swift-commit mailing list