static int doRunInstance(struct nc_state_t *nc, ncMetadata * pMeta, char *uuid, char *instanceId, char *reservationId, virtualMachine * params,
                         char *imageId, char *imageURL, char *kernelId, char *kernelURL, char *ramdiskId, char *ramdiskURL, char *ownerId,
                         char *accountId, char *keyName, netConfig * netparams, char *userData, char *launchIndex, char *platform, int expiryTime,
                         char **groupNames, int groupNamesSize, ncInstance ** outInstPtr)
{
    int ret = EUCA_OK;
    ncInstance *instance = NULL;
    netConfig ncnet = { 0 };

    *outInstPtr = NULL;

    memcpy(&ncnet, netparams, sizeof(netConfig));

    // check as much as possible before forking off and returning
    sem_p(inst_sem);
    instance = find_instance(&global_instances, instanceId);
    sem_v(inst_sem);
    if (instance) {
        if (instance->state == TEARDOWN) {
            // fully cleaned up, so OK to revive it, e.g., with euca-start-instance
            remove_instance(&global_instances, instance);
            free_instance(&instance);
        } else {
            LOGERROR("[%s] instance already running\n", instanceId);
            return EUCA_ERROR;         //! @todo return meaningful error codes?
        }
    }

    instance = allocate_instance(uuid, instanceId, reservationId, params, instance_state_names[PENDING], PENDING, pMeta->userId, ownerId, accountId,
                                 &ncnet, keyName, userData, launchIndex, platform, expiryTime, groupNames, groupNamesSize);
    if (instance == NULL) {
        LOGERROR("[%s] could not allocate instance struct\n", instanceId);
        return EUCA_MEMORY_ERROR;
    }
    instance->launchTime = time(NULL);

    // parse and sanity-check the virtual boot record
    if (vbr_parse(&(instance->params), pMeta) != EUCA_OK) {
        ret = EUCA_ERROR;
        goto error;
    }

    change_state(instance, STAGING);

    sem_p(inst_sem);
    int error = add_instance(&global_instances, instance);
    copy_instances();
    sem_v(inst_sem);
    if (error) {
        LOGERROR("[%s] could not save instance struct\n", instanceId);
        ret = EUCA_ERROR;
        goto error;
    }
    // do the potentially long tasks in a thread
    pthread_attr_t *attr = (pthread_attr_t *) EUCA_ZALLOC(1, sizeof(pthread_attr_t));
    if (!attr) {
        LOGERROR("[%s] out of memory\n", instanceId);
        ret = EUCA_MEMORY_ERROR;
        goto error;
    }
    pthread_attr_init(attr);
    pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);

    if (pthread_create(&(instance->tcb), attr, startup_thread, (void *)instance)) {
        pthread_attr_destroy(attr);
        LOGERROR("[%s] failed to spawn a VM startup thread\n", instanceId);
        sem_p(inst_sem);
        remove_instance(&global_instances, instance);
        copy_instances();
        sem_v(inst_sem);
        EUCA_FREE(attr);
        ret = EUCA_THREAD_ERROR;
        goto error;
    }
    pthread_attr_destroy(attr);
    EUCA_FREE(attr);

    *outInstPtr = instance;
    return EUCA_OK;

error:
    free_instance(&instance);
    return (ret);
}
static int doRunInstance(struct nc_state_t *nc, ncMetadata * pMeta, char *uuid, char *instanceId, char *reservationId, virtualMachine * params,
                         char *imageId, char *imageURL, char *kernelId, char *kernelURL, char *ramdiskId, char *ramdiskURL, char *ownerId,
                         char *accountId, char *keyName, netConfig * netparams, char *userData, char *launchIndex, char *platform, int expiryTime,
                         char **groupNames, int groupNamesSize, ncInstance ** outInstPtr)
{
    int ret = EUCA_OK;
    ncInstance *instance = NULL;
    netConfig ncnet = { 0 };

    *outInstPtr = NULL;

    memcpy(&ncnet, netparams, sizeof(netConfig));

     
    sem_p(inst_sem);
    instance = find_instance(&global_instances, instanceId);
    sem_v(inst_sem);
    if (instance) {
        if (instance->state == TEARDOWN) {
             
            remove_instance(&global_instances, instance);
            free_instance(&instance);
        } else {
            LOGERROR("[%s] instance already running\n", instanceId);
            return EUCA_ERROR;          
        }
    }

    instance = allocate_instance(uuid, instanceId, reservationId, params, instance_state_names[PENDING], PENDING, pMeta->userId, ownerId, accountId,
                                 &ncnet, keyName, userData, launchIndex, platform, expiryTime, groupNames, groupNamesSize);
    if (instance == NULL) {
        LOGERROR("[%s] could not allocate instance struct\n", instanceId);
        return EUCA_MEMORY_ERROR;
    }
    instance->launchTime = time(NULL);

     
    if (vbr_parse(&(instance->params), pMeta) != EUCA_OK) {
        ret = EUCA_ERROR;
        goto error;
    }

    change_state(instance, STAGING);

    sem_p(inst_sem);
    int error = add_instance(&global_instances, instance);
    copy_instances();
    sem_v(inst_sem);
    if (error) {
        LOGERROR("[%s] could not save instance struct\n", instanceId);
        ret = EUCA_ERROR;
        goto error;
    }
     
    pthread_attr_t *attr = (pthread_attr_t *) EUCA_ZALLOC(1, sizeof(pthread_attr_t));
    if (!attr) {
        LOGERROR("[%s] out of memory\n", instanceId);
        ret = EUCA_MEMORY_ERROR;
        goto error;
    }
    pthread_attr_init(attr);
    pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);

    if (pthread_create(&(instance->tcb), attr, startup_thread, (void *)instance)) {
        pthread_attr_destroy(attr);
        LOGERROR("[%s] failed to spawn a VM startup thread\n", instanceId);
        sem_p(inst_sem);
        remove_instance(&global_instances, instance);
        copy_instances();
        sem_v(inst_sem);
        EUCA_FREE(attr);
        ret = EUCA_THREAD_ERROR;
        goto error;
    }
    pthread_attr_destroy(attr);
    EUCA_FREE(attr);

    *outInstPtr = instance;
    return EUCA_OK;

error:
    free_instance(&instance);
    return (ret);
}