void session_terminate(session_t *session) { union Key k = { .u64 = session->id }; qlock(&session_map_mutex); mapremove(&session_map, k); session->status = SESSION_TERMINATED; qunlock(&session_map_mutex); } void session_pause(session_t *session, bool pause) { session->status = SESSION_PAUSED; } void session_remove_ref(session_t *session) { if (session == NULL) { return; } session_lock(session); session->refcount--; if (session->refcount == 0 && session->status == SESSION_TERMINATED) { if (session->data_cleanup != NULL) { session->data_cleanup(session); } free(session); if (chattyv2g) fprintf(stderr, "Succesfully freed session\n"); // No need to unlock if refcount 0, since it can never increase from this point since it has been removed from the map. } else if (session->refcount < 0) { if (chattyv2g) fprintf(stderr, "session_remove_ref: Negative session ref-count. THIS IS BAD!\n"); } else { session_unlock(session); } }
session_t *session_lookup(uint64_t sessionid) { if (sessionid == 0) { return NULL; } union Key k = {.u64 = sessionid}; qlock(&session_map_mutex); session_t **sessionpp = (session_t**)mapfind(&session_map, k); if (sessionpp == NULL) { printf("session_lookup: invalid session\n"); return NULL; } session_lock(*sessionpp); (*sessionpp)->refcount++; if ((*sessionpp)->refcount > 4) { printf("session_lookup: %d references to the same session, code error is likely\n", (*sessionpp)->refcount); } session_unlock(*sessionpp); qunlock(&session_map_mutex); return *sessionpp; }
/* This returns vnode with ioref */ static vnode_t cttyvp(proc_t p) { vnode_t vp; int vid; struct session *sessp; sessp = proc_session(p); session_lock(sessp); vp = (p->p_flag & P_CONTROLT ? sessp->s_ttyvp : NULLVP); vid = sessp->s_ttyvid; session_unlock(sessp); session_rele(sessp); if (vp != NULLVP) { /* cannot get an IO reference, return NULLVP */ if (vnode_getwithvid(vp, vid) != 0) vp = NULLVP; } return(vp); }
// 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; }
/* * Device close routine */ int spec_close(struct vnop_close_args *ap) { struct vnode *vp = ap->a_vp; dev_t dev = vp->v_rdev; int (*devclose)(dev_t, int, int, struct proc *); int mode, error; int flags = ap->a_fflag; struct proc *p = vfs_context_proc(ap->a_context); struct session *sessp; switch (vp->v_type) { case VCHR: /* * Hack: a tty device that is a controlling terminal * has a reference from the session structure. * We cannot easily tell that a character device is * a controlling terminal, unless it is the closing * process' controlling terminal. In that case, * if the reference count is 1 (this is the very * last close) */ sessp = proc_session(p); if (sessp != SESSION_NULL) { if ((vcount(vp) == 1) && (vp == sessp->s_ttyvp)) { session_lock(sessp); sessp->s_ttyvp = NULL; sessp->s_ttyvid = 0; sessp->s_ttyp = TTY_NULL; sessp->s_ttypgrpid = NO_PID; session_unlock(sessp); vnode_rele(vp); } session_rele(sessp); } devclose = cdevsw[major(dev)].d_close; mode = S_IFCHR; /* * close on last reference or on vnode revoke call */ if ((flags & IO_REVOKE) != 0) break; if (vcount(vp) > 0) return (0); break; case VBLK: /* * Since every use (buffer, vnode, swap, blockmap) * holds a reference to the vnode, and because we mark * any other vnodes that alias this device, when the * sum of the reference counts on all the aliased * vnodes descends to zero, we are on last close. */ if (vcount(vp) > 0) return (0); /* * On last close of a block device (that isn't mounted) * we must invalidate any in core blocks, so that * we can, for instance, change floppy disks. */ if ((error = spec_fsync_internal(vp, MNT_WAIT, ap->a_context))) return (error); error = buf_invalidateblks(vp, BUF_WRITE_DATA, 0, 0); if (error) return (error); devclose = bdevsw[major(dev)].d_close; mode = S_IFBLK; break; default: panic("spec_close: not special"); return(EBADF); } return ((*devclose)(dev, flags, mode, p)); }
int cttyopen(dev_t dev, int flag, __unused int mode, proc_t p) { vnode_t ttyvp = cttyvp(p); struct vfs_context context; int error = 0; int cttyflag, doclose = 0; struct session *sessp; if (ttyvp == NULL) return (ENXIO); context.vc_thread = current_thread(); context.vc_ucred = kauth_cred_proc_ref(p); sessp = proc_session(p); session_lock(sessp); cttyflag = sessp->s_flags & S_CTTYREF; session_unlock(sessp); /* * A little hack--this device, used by many processes, * happens to do an open on another device, which can * cause unhappiness if the second-level open blocks indefinitely * (as could be the case if the master side has hung up). Since * we know that this driver doesn't care about the serializing * opens and closes, we can drop the lock. To avoid opencount leak, * open the vnode only for the first time. */ if (cttyflag == 0) { devsw_unlock(dev, S_IFCHR); error = VNOP_OPEN(ttyvp, flag, &context); devsw_lock(dev, S_IFCHR); if (error) goto out; /* * If S_CTTYREF is set, some other thread did an open * and was able to set the flag, now perform a close, else * set the flag. */ session_lock(sessp); if (cttyflag == (sessp->s_flags & S_CTTYREF)) sessp->s_flags |= S_CTTYREF; else doclose = 1; session_unlock(sessp); /* * We have to take a reference here to make sure a close * gets called during revoke. Note that once a controlling * tty gets opened by this driver, the only way close will * get called is when the session leader , whose controlling * tty is ttyvp, exits and vnode is revoked. We cannot * redirect close from this driver because underlying controlling * terminal might change and close may get redirected to a * wrong vnode causing panic. */ if (doclose) { devsw_unlock(dev, S_IFCHR); VNOP_CLOSE(ttyvp, flag, &context); devsw_lock(dev, S_IFCHR); } else { error = vnode_ref(ttyvp); } } out: session_rele(sessp); vnode_put(ttyvp); kauth_cred_unref(&context.vc_ucred); return (error); }