void reader_writer_lock::start_read(scoped_lock_read *I) { ITT_NOTIFY(sync_prepare, this); I->next = reader_head.fetch_and_store(I); if (!I->next) { // first arriving reader in my group; set RFLAG, test writer flags // unblock and/or update statuses of non-blocking readers if (!(fetch_and_or(rdr_count_and_flags, RFLAG) & (WFLAG1+WFLAG2))) { // no writers unblock_readers(); } } __TBB_ASSERT(I->status == waiting || I->status == active, "Lock requests should be waiting or active before blocking."); spin_wait_while_eq(I->status, waiting); // block if (I->next) { __TBB_ASSERT(I->next->status == waiting, NULL); rdr_count_and_flags += RC_INCR; I->next->status = active; // wake successor } ITT_NOTIFY(sync_acquired, this); }
void reader_writer_lock::set_next_writer(scoped_lock *W) { writer_head = W; if (W->status == waiting_nonblocking) { if (rdr_count_and_flags.compare_and_swap(WFLAG1+WFLAG2, 0) == 0) { W->status = active; } } else { if (fetch_and_or(rdr_count_and_flags, WFLAG1) & RFLAG) { // reader present spin_wait_until_and(rdr_count_and_flags, WFLAG2); // block until readers set WFLAG2 } else { // no reader in timing window __TBB_AtomicOR(&rdr_count_and_flags, WFLAG2); } spin_wait_while_geq(rdr_count_and_flags, RC_INCR); // block until readers finish W->status = active; } }
EA *ea_new(const char *path, uint64_t bsize, int basyncs, uint64_t *size, uint64_t *bcount, uint64_t vlun) { int rc = 0; size_t plen = 0; uint8_t *store = NULL; EA *ea = NULL; chunk_id_t chkid = NULL_CHUNK_ID; chunk_ext_arg_t ext = 0; if (!(fetch_and_or(&cflsh_blk_lib_init,1))) { // We need to call cblk_init once before // we use any other cblk_ interfaces rc = cblk_init(NULL,0); if (rc) { KV_TRC_FFDC(pAT, "cblk_init failed path %s bsize %"PRIu64" " "size %"PRIu64" bcount %"PRIu64", errno = %d", path, bsize, *size, *bcount, errno); goto error_exit; } } ea = am_malloc(sizeof(EA)); if (NULL == ea) { KV_TRC_FFDC(pAT, "Out of memory path %s bsize %"PRIu64" size %"PRIu64" " "bcount %"PRIu64", errno = %d", path, bsize, *size, *bcount, errno); goto error_exit; } // We need to check the path parameter to see if // we are going to use memory or a file/capi // device (to be determined by the block layer) if ( (NULL == path) || (strlen(path) == 0) ) { KV_TRC(pAT, "EA_STORE_TYPE_MEMORY"); // Using memory for store ea->st_type = EA_STORE_TYPE_MEMORY; store = malloc(*size); if (NULL == store) { errno = ENOMEM; KV_TRC_FFDC(pAT, "Out of memory for store path %s bsize %"PRIu64" " "size %"PRIu64" bcount %"PRIu64", errno = %d", path, bsize, *size, *bcount, errno); goto error_exit; } *bcount = ((*size) / bsize); ea->st_memory = store; } else { KV_TRC(pAT, "EA_STORE_TYPE_FILE(%s)", path); // Using a file. We don't care if it's an actual // file or a CAPI device, we let block layer // decide and we just use the chunk ID that is // passed back from the cblk_open call. ea->st_type = EA_STORE_TYPE_FILE; // Check to see if we need to create the store on a // physical or virtual LUN. Previously, in GA1, // we keyed off the size and if it was 0, then we // asked for the LUN to be physical. Now, the user // can specify with a flag. if ( vlun == 0 ) { KV_TRC(pAT, "cblk_open PHYSICAL LUN: %s", path); chkid = cblk_open(path, basyncs, O_RDWR, ext, CBLK_OPN_NO_INTRP_THREADS); if (NULL_CHUNK_ID == chkid) { printf("cblk_open physical lun failed\n"); KV_TRC_FFDC(pAT, "cblk_open phys lun failed path:%s bsize:%ld " "size:%ld bcount:%ld, errno:%d", path, bsize, *size, *bcount, errno); goto error_exit; } rc = cblk_get_size(chkid, (size_t *)bcount, 0); if ( (rc != 0) || (*bcount == 0) ) { // An error was encountered, close the chunk cblk_close(chkid, 0); chkid = NULL_CHUNK_ID; KV_TRC_FFDC(pAT, "cblk_get_size failed path %s bsize %"PRIu64" " "size %"PRIu64" bcount %"PRIu64", errno = %d", path, bsize, *size, *bcount, errno); goto error_exit; } // Set the size to be returned *size = *bcount * bsize; } else { KV_TRC(pAT, "cblk_open VIRTUAL LUN: %s", path); chkid = cblk_open(path, basyncs, O_RDWR, ext, CBLK_OPN_VIRT_LUN|CBLK_OPN_NO_INTRP_THREADS); if (NULL_CHUNK_ID == chkid) { printf("cblk_open virtual lun failed\n"); KV_TRC_FFDC(pAT, "cblk_open virt lun failed path:%s bsize:%ld " "size:%ld bcount:%ld, errno:%d", path, bsize, *size, *bcount, errno); goto error_exit; } // A specific size was passed in so we try to set the // size of the chunk. *bcount = *size / bsize; rc = cblk_set_size(chkid, (size_t)*bcount, 0); if ( rc != 0 ) { printf("cblk_set_size failed for %ld\n", *bcount); // An error was encountered, close the chunk cblk_close(chkid, 0); chkid = NULL_CHUNK_ID; KV_TRC_FFDC(pAT, "cblk_set_size failed path %s bsize %"PRIu64" " "size %"PRIu64" bcount %"PRIu64", errno = %d", path, bsize, *size, *bcount, errno); goto error_exit; } } // Save off the chunk ID and the device name ea->st_flash = chkid; plen = strlen(path) + 1; ea->st_device = (char *)am_malloc(plen); if (!ea->st_device) { cblk_close(chkid, 0); KV_TRC_FFDC(pAT, "MALLOC st_device failed (%s) plen=%ld errno:%d", path, plen, errno); goto error_exit; } memset(ea->st_device, 0, plen); strncpy(ea->st_device, path, plen); } // Fill in the EA struct pthread_rwlock_init(&(ea->ea_rwlock), NULL); ea->bsize = bsize; ea->bcount = *bcount; ea->size = *size; KV_TRC(pAT, "path %s bsize %"PRIu64" size %"PRIu64" bcount %"PRIu64"", path, bsize, *size, *bcount); goto done; error_exit: am_free(ea); ea = NULL; if (!errno) {KV_TRC_FFDC(pAT, "UNSET_ERRNO"); errno=ENOSPC;} done: return ea; }