// userdata, is a curl_iovec_t. This is set to be passed into this function, when we // call CURLOPT_WRITEDATA in curl_preadv and curl_readv. // FUTURE: If we have filled the iovec, but have not finished reading from the curl // handle, pause it (i.e., return CURL_WRITE_PAUSE). static size_t buf_writer(char* ptr_data, size_t size, size_t nmemb, void* userdata) { size_t realsize = size*nmemb; size_t real_realsize = realsize; struct curl_iovec_t* ret = ((struct curl_iovec_t *)userdata); // so that we can "seek" when we cannot request byteranges if (realsize < ret->offset) { ret->offset -= realsize; return realsize; } else { // nop when we are done -- non-zero the first time through ptr_data = &(ptr_data[ret->offset]); realsize -= ret->offset; ret->offset = 0; } // The amount that we have been given by curl is more than we can stick into a // single iovbuf. So we need to go from one iovbuf to the other while (realsize > ret->vec[ret->curr].iov_len*size - ret->amt_read) { // This cast to char* is to get rid "subscript of pointer to incomplete type" warnings chpl_memcpy(&(((char*)ret->vec[ret->curr].iov_base)[ret->amt_read]), ptr_data, ret->vec[ret->curr].iov_len*size - ret->amt_read); ret->total_read += (ret->vec[ret->curr].iov_len*size - ret->amt_read); realsize -= ret->vec[ret->curr].iov_len*size - ret->amt_read; ptr_data = &(ptr_data[(ret->vec[ret->curr].iov_len*size - ret->amt_read)]); // Reset the amount that we have read into this vector. ret->amt_read = 0; if (ret->curr == ret->count-1) { // last iovbuf in this vector, so stop reading return 0; // stop reading } else { // go to the next buf in this vector ret->curr++; } } // The amount of data that we have been given by curl is <= to the amount of space // that we have left in this iovbuf. So we can simply read it all in. if (realsize <= (ret->vec[ret->curr].iov_len*size - ret->amt_read)) { chpl_memcpy(&(((char*)ret->vec[ret->curr].iov_base)[ret->amt_read]), ptr_data, realsize); ret->total_read += realsize; ret->amt_read += realsize; // We have fully populated this iovbuf if (ret->vec[ret->curr].iov_len*size == ret->amt_read) { if (ret->curr == ret->count -1) // last iovbuf in this vector return 0; // stop reading else { // else, step to the next buf. ret->curr++; ret->amt_read = 0; } } } return real_realsize; }
void chpl_comm_ofi_oob_allgather(void* const in, void* out, size_t len) { if (chpl_numNodes == 1) { chpl_memcpy(out, in, len); } else { INTERNAL_ERROR_V("multi-locale allgather not supported"); } }
// Note that this function can be called in parallel and more notably it can be // called with non-monotonic pid's. e.g. this may be called with pid 27, and // then pid 2, so it has to ensure that the privatized array has at least pid+1 // elements. Be __very__ careful if you have to update it. void chpl_newPrivatizedClass(void* v, int64_t pid) { chpl_sync_lock(&privatizationSync); // initialize array to a default size if (chpl_privateObjects == NULL) { chpl_capPrivateObjects = 2*max(pid, 4); chpl_privateObjects = chpl_mem_allocMany(chpl_capPrivateObjects, sizeof(void *), CHPL_RT_MD_COMM_PRV_OBJ_ARRAY, 0, 0); } else { // if we're out of space, double (or more) the array size if (pid >= chpl_capPrivateObjects) { void** tmp; int64_t oldCap; oldCap = chpl_capPrivateObjects; chpl_capPrivateObjects = 2*max(pid, oldCap); tmp = chpl_mem_allocMany(chpl_capPrivateObjects, sizeof(void *), CHPL_RT_MD_COMM_PRV_OBJ_ARRAY, 0, 0); chpl_memcpy((void*)tmp, (void*)chpl_privateObjects, (oldCap)*sizeof(void*)); chpl_privateObjects = tmp; // purposely leak old copies of chpl_privateObject to avoid the need to // lock chpl_getPrivatizedClass; TODO: fix with lock free data structure } } chpl_privateObjects[pid] = v; chpl_sync_unlock(&privatizationSync); }
chpl_comm_nb_handle_t chpl_comm_get_nb(void* addr, c_nodeid_t node, void* raddr, size_t size, int32_t typeIndex, int ln, int32_t fn) { assert(node == 0); chpl_memcpy(addr, raddr, size); return NULL; }
void chpl_task_taskCall(chpl_fn_p fp, void* arg, size_t arg_size, c_sublocid_t subloc, int lineno, int32_t filename) { void *arg_copy = NULL; if (arg != NULL) { arg_copy = chpl_mem_allocMany(1, arg_size, CHPL_RT_MD_TASK_ARG, 0, 0); chpl_memcpy(arg_copy, arg, arg_size); } taskCallBody(fp, NULL, arg_copy, subloc, false, lineno, filename); }
// We want to upload data from the iovec passed into curl_writev. We populate a // curl_iovec_t in curl_writev, and set it to be passed in when we call // CURLOPT_READDATA. Note, that we can only return a chunk of memory at most // size*nmemb big to curl (i.e., sizeof(ptr) <= size*nmemb after this function is // called by CURL). static size_t read_data(void *ptr, size_t size, size_t nmemb, void *userp) { size_t realsize = size*nmemb; struct curl_iovec_t* ret = ((struct curl_iovec_t *)userp); if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1) || (ret->curr >= ret->count)) { return 0; // stop putting data } // We can upload more than one iovbuf at once, so do it. while (realsize > ret->vec[ret->curr].iov_len*size - ret->amt_read) { chpl_memcpy(ptr, &(((char*)ret->vec[ret->curr].iov_base)[ret->amt_read]), ret->vec[ret->curr].iov_len*size - ret->amt_read); ret->total_read += (ret->vec[ret->curr].iov_len*size - ret->amt_read); realsize -= ret->vec[ret->curr].iov_len*size - ret->amt_read; ptr = &(((char*)ptr)[(ret->vec[ret->curr].iov_len*size - ret->amt_read)]); // Reset the amount that we have read out of this vector. ret->amt_read = 0; // go to the next vector ret->curr++; if (ret->curr >= ret->count) return ret->total_read; } // The amount of data that we need to hand to curl is <= the amount of space // that we have left in this iovbuf, so we have to be careful not to exceed it if (realsize <= (ret->vec[ret->curr].iov_len*size - ret->amt_read)) { chpl_memcpy(ptr, &(((char*)ret->vec[ret->curr].iov_base)[ret->amt_read]), realsize); ret->total_read += realsize; ret->amt_read += realsize; // We have fully read this iovbuf if (ret->vec[ret->curr].iov_len*size == ret->amt_read) { ret->curr++; ret->amt_read = 0; } } return ret->total_read; }
void string_from_c_string(chpl_string *ret, c_string str, int haslen, int64_t len, int32_t lineno, chpl_string filename) { char* s; if( str == NULL ) { *ret = NULL; return; } if( ! haslen ) len = strlen(str); s = (char*)chpl_mem_alloc(len+1, CHPL_RT_MD_STRING_COPY_DATA, lineno, filename); chpl_memcpy(s, str, len); s[len] = '\0'; *ret = s; }
// Write from curl to a string. Note that userdata is a str_t, since nuch as we have // to keep track of how much we read in buf_writer, we have to keep track of how // long our string is so that we cann lengthen it via realloc as we need to. static size_t chpl_curl_write_string(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct str_t *str = (struct str_t *)userp; str->mem = (char*)qio_realloc(str->mem, str->size + realsize + 1); if(str->mem == NULL) { return 0; } chpl_memcpy(&(str->mem[str->size]), contents, realsize); str->size += realsize; str->mem[str->size] = 0; return realsize; }
void wide_string_from_c_string(chpl____wide_chpl_string *ret, c_string str, int haslen, int64_t len, int32_t lineno, chpl_string filename) { char* s; ret->locale = chpl_gen_getLocaleID(); if( str == NULL ) { ret->addr = NULL; ret->size = 0; return; } if( ! haslen ) len = strlen(str); s = chpl_mem_alloc(len+1, CHPL_RT_MD_STRING_COPY_DATA, lineno, filename); chpl_memcpy(s, str, len); s[len] = '\0'; ret->addr = s; ret->size = len + 1; // this size includes the terminating NUL }
// un-macro'd CHPL_COMM_WIDE_GET_STRING void chpl_comm_wide_get_string(chpl_string* local, struct chpl_chpl____wide_chpl_string_s* x, int32_t tid, int32_t lineno, chpl_string filename) { char* chpl_macro_tmp; if (x->addr == NULL) { *local = NULL; return; } chpl_macro_tmp = chpl_mem_calloc(x->size, CHPL_RT_MD_GET_WIDE_STRING, lineno, filename); if (chpl_nodeID == chpl_rt_nodeFromLocaleID(x->locale)) chpl_memcpy(chpl_macro_tmp, x->addr, x->size); else chpl_gen_comm_get((void*) &(*chpl_macro_tmp), chpl_rt_nodeFromLocaleID(x->locale), (void*)(x->addr), sizeof(char), tid, x->size, lineno, filename); *local = chpl_macro_tmp; }
// This copies the remote string data into a local wide string representation // of the same. // This routine performs a deep copy of the character array data // after fetching the string descriptor from the remote node. (The char* // field in the local copy of the remote descriptor has no meaning in the // context of the local node, since it refers to elements in the address // space on the remote node.) // In chpl_comm_wide_get_string() a buffer of the right size is allocated // to receive the bytes copied from the remote node. This buffer will be leaked, // since no corresponding free is added to the generated code. void chpl_gen_comm_wide_string_get(void *addr, c_nodeid_t node, void *raddr, size_t size, int32_t typeIndex, int ln, int32_t fn) { // This part just copies the descriptor. if (chpl_nodeID == node) { chpl_memcpy(addr, raddr, size); } else { chpl_gen_comm_get(addr, node, raddr, size, typeIndex, ln, fn); } // And now we copy the bytes in the string itself. { struct chpl_chpl____wide_chpl_string_s* local_str = (struct chpl_chpl____wide_chpl_string_s*) addr; // Accessing the addr field of the incomplete struct declaration // would not work in this context except that this function // is always inlined. chpl_comm_wide_get_string((chpl_string*) &(local_str->addr), local_str, typeIndex, ln, fn); // The bytes live locally, so we have to update the locale. local_str->locale = chpl_gen_getLocaleID(); } }