// session->mutex must be locked static int wait_for_playlist_loaded(php_spotify_playlist *playlist) { struct timespec ts; int err = 0; php_spotify_session *session; assert(playlist != NULL); session = playlist->session; DEBUG_PRINT("wait_for_playlist_loaded start\n"); // Block for a max of SPOTIFY_TIMEOUT seconds clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += SPOTIFY_TIMEOUT; request_lock(); while(err == 0) { DEBUG_PRINT("wait_for_playlist_loaded loop\n"); int loaded; session_lock(session); loaded = sp_playlist_is_loaded(playlist->playlist); session_unlock(session); if (loaded) break; // Wait until a callback is fired err = request_sleep_lock(&ts); } request_unlock(); DEBUG_PRINT("wait_for_playlist_loaded end(%d)\n", err); return err; }
bool DoLock(CSocketIOPtr s,size_t client, char *param) { ClientLock lock; char *flags, *path,*p; unsigned uFlags=0; size_t lock_to_wait_for; if(LockClientMap[client].state!=lcActive) { s->printf("001 FAIL Unexpected 'Lock' command\n"); return false; } path = strchr(param,'|'); if(!path) { s->printf("001 FAIL Lock command expects <flags>|<path>\n"); return false; } *(path++)='\0'; flags = param; while((p=lock_strchr(flags,' '))!=NULL) { char c=*p; *p='\0'; if(!strcmp(flags,"Read")) uFlags|=lfRead; else if(!strcmp(flags,"Write")) uFlags|=lfWrite; else if(!strcmp(flags,"Advisory")) uFlags|=lfAdvisory; else if(!strcmp(flags,"Full")) uFlags|=lfFull; else { s->printf("001 FAIL Unknown flag '%s'\n",flags); return false; } if(c) flags=p+1; else break; } if(!(uFlags&lfRead) && !(uFlags&lfWrite)) { s->printf("001 FAIL Must specify read or write\n"); return false; } if(strncmp(path,LockClientMap[client].root.c_str(),LockClientMap[client].root.size())) { DEBUG("(#%d) Lock Fail %s not within %s\n",(int)client,path,LockClientMap[client].root.c_str()); s->printf("001 FAIL Lock not within repository\n"); return false; } if(request_lock(client,path,uFlags,lock_to_wait_for)) { VersionMapType ver; size_t newId = ++global_lockId; if(((uFlags&lfFull) && (uFlags&lfRead)) || (uFlags&lfWrite)) { TransactionListType::const_iterator i = std::find(TransactionList.begin(), TransactionList.end(), path); if(i!=TransactionList.end()) { /* This is where atomicity really 'happens' */ if(i->owner!=client && /* Not us */ LockClientMap.find(i->owner)!=LockClientMap.end() && /* Exists */ TimeIntersects(LockClientMap[i->owner].starttime,LockClientMap[i->owner].endtime, LockClientMap[client].starttime,LockClientMap[client].endtime)) /* Overlaps us */ { printf("Found version %s:%s\n",i->branch.c_str(),i->oldversion.c_str()); ver[i->branch]=i->oldversion; /* If a transaction is still in progress and a version has been committed, we can't allow even an advisory write yet. */ if(uFlags&lfWrite) { DEBUG("(#%d) Lock request on %s (%s) (wait for transaction by client %d)\n",(int)client,path,FlagToString(uFlags),(unsigned)i->owner); s->printf("002 WAIT Lock busy|%s|%s|%s\n",LockClientMap[i->owner].user.c_str(),LockClientMap[i->owner].client_host.c_str(),path); return true; } } } } DEBUG("(#%d) Lock request on %s (%s) (granted %u)\n",(int)client,path,FlagToString(uFlags),(unsigned)newId); s->printf("000 OK Lock granted (%u)\n",(unsigned)newId); LockMap[newId].flags=uFlags; LockMap[newId].path=path; LockMap[newId].length=strlen(path); LockMap[newId].owner=client; LockMap[newId].versions = ver; } else { DEBUG("(#%d) Lock request on %s (%s) (wait for %u)\n",(int)client,path,FlagToString(uFlags),(unsigned)lock_to_wait_for); s->printf("002 WAIT Lock busy|%s|%s|%s\n",LockClientMap[LockMap[lock_to_wait_for].owner].user.c_str(),LockClientMap[LockMap[lock_to_wait_for].owner].client_host.c_str(),LockMap[lock_to_wait_for].path.c_str()); } return true; }