您当前的位置:首页 > IT编程 > C++
| C语言 | Java | VB | VC | python | Android | TensorFlow | C++ | oracle | 学术与代码 | cnn卷积神经网络 | gnn | 图像修复 | Keras | 数据集 | Neo4j | 自然语言处理 | 深度学习 | 医学CAD | 医学影像 | 超参数 | pointnet | pytorch | 异常检测 | Transformers | 情感分类 | 知识图谱 |

自学教程:C++ tty_unlock函数代码示例

51自学网 2021-06-03 09:00:42
  C++
这篇教程C++ tty_unlock函数代码示例写得很实用,希望能帮到您。

本文整理汇总了C++中tty_unlock函数的典型用法代码示例。如果您正苦于以下问题:C++ tty_unlock函数的具体用法?C++ tty_unlock怎么用?C++ tty_unlock使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。

在下文中一共展示了tty_unlock函数的25个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。

示例1: ptmx_open

static int ptmx_open(struct inode *inode, struct file *filp){	struct tty_struct *tty;	int retval;	int index;	nonseekable_open(inode, filp);	/* We refuse fsnotify events on ptmx, since it's a shared resource */	filp->f_mode |= FMODE_NONOTIFY;	retval = tty_alloc_file(filp);	if (retval)		return retval;	/* find a device that is not in use. */	tty_lock();	index = devpts_new_index(inode);	tty_unlock();	if (index < 0) {		retval = index;		goto err_file;	}	mutex_lock(&tty_mutex);	tty_lock();	tty = tty_init_dev(ptm_driver, index, 1);	mutex_unlock(&tty_mutex);	if (IS_ERR(tty)) {		retval = PTR_ERR(tty);		goto out;	}	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */	tty_add_file(tty, filp);	retval = devpts_pty_new(inode, tty->link);	if (retval)		goto err_release;	retval = ptm_driver->ops->open(tty, filp);	if (retval)		goto err_release;	tty_unlock();	return 0;err_release:	tty_unlock();	tty_release(inode, filp);	return retval;out:	devpts_kill_index(inode, index);	tty_unlock();err_file:	tty_free_file(filp);	return retval;}
开发者ID:791254467,项目名称:u8500_kernel,代码行数:59,


示例2: briq_panel_open

static int briq_panel_open(struct inode *ino, struct file *filep){	tty_lock();	/* enforce single access, vfd_is_open is protected by BKL */	if (vfd_is_open) {		tty_unlock();		return -EBUSY;	}	vfd_is_open = 1;	tty_unlock();	return 0;}
开发者ID:1703011,项目名称:asuswrt-merlin,代码行数:13,


示例3: ptsdev_poll

static intptsdev_poll(struct file *fp, int events, struct ucred *active_cred,    struct thread *td){	struct tty *tp = fp->f_data;	struct pts_softc *psc = tty_softc(tp);	int revents = 0;	tty_lock(tp);	if (psc->pts_flags & PTS_FINISHED) {		/* Slave device is not opened. */		tty_unlock(tp);		return ((events & (POLLIN|POLLRDNORM)) | POLLHUP);	}	if (events & (POLLIN|POLLRDNORM)) {		/* See if we can getc something. */		if (ttydisc_getc_poll(tp) ||		    (psc->pts_flags & PTS_PKT && psc->pts_pkt))			revents |= events & (POLLIN|POLLRDNORM);	}	if (events & (POLLOUT|POLLWRNORM)) {		/* See if we can rint something. */		if (ttydisc_rint_poll(tp))			revents |= events & (POLLOUT|POLLWRNORM);	}	/*	 * No need to check for POLLHUP here. This device cannot be used	 * as a callout device, which means we always have a carrier,	 * because the master is.	 */	if (revents == 0) {		/*		 * This code might look misleading, but the naming of		 * poll events on this side is the opposite of the slave		 * device.		 */		if (events & (POLLIN|POLLRDNORM))			selrecord(td, &psc->pts_outpoll);		if (events & (POLLOUT|POLLWRNORM))			selrecord(td, &psc->pts_inpoll);	}	tty_unlock(tp);	return (revents);}
开发者ID:JasonFord53,项目名称:freebsd,代码行数:50,


示例4: nmdm_task_tty

static voidnmdm_task_tty(void *arg, int pending __unused){	struct tty *tp, *otp;	struct nmdmpart *np = arg;	char c;	tp = np->np_tty;	tty_lock(tp);	if (tty_gone(tp)) {		tty_unlock(tp);		return;	}	otp = np->np_other->np_tty;	KASSERT(otp != NULL, ("NULL otp in nmdmstart"));	KASSERT(otp != tp, ("NULL otp == tp nmdmstart"));	if (np->np_other->np_dcd) {		if (!tty_opened(tp)) {			np->np_other->np_dcd = 0;			ttydisc_modem(otp, 0);		}	} else {		if (tty_opened(tp)) {			np->np_other->np_dcd = 1;			ttydisc_modem(otp, 1);		}	}	/* This may happen when we are in detach process. */	if (tty_gone(otp)) {		tty_unlock(otp);		return;	}	while (ttydisc_rint_poll(otp) > 0) {		if (np->np_rate && !np->np_quota)			break;		if (ttydisc_getc(tp, &c, 1) != 1)			break;		np->np_quota--;		ttydisc_rint(otp, c, 0);	}	ttydisc_rint_done(otp);	tty_unlock(tp);}
开发者ID:ele7enxxh,项目名称:dtrace-pf,代码行数:48,


示例5: spk_ttyio_initialise_ldisc

static int spk_ttyio_initialise_ldisc(struct spk_synth *synth){	int ret = 0;	struct tty_struct *tty;	struct ktermios tmp_termios;	dev_t dev;	ret = get_dev_to_use(synth, &dev);	if (ret)		return ret;	tty = tty_kopen(dev);	if (IS_ERR(tty))		return PTR_ERR(tty);	if (tty->ops->open)		ret = tty->ops->open(tty, NULL);	else		ret = -ENODEV;	if (ret) {		tty_unlock(tty);		return ret;	}	clear_bit(TTY_HUPPED, &tty->flags);	/* ensure hardware flow control is enabled */	get_termios(tty, &tmp_termios);	if (!(tmp_termios.c_cflag & CRTSCTS)) {		tmp_termios.c_cflag |= CRTSCTS;		tty_set_termios(tty, &tmp_termios);		/*		 * check c_cflag to see if it's updated as tty_set_termios may not return		 * error even when no tty bits are changed by the request.		 */		get_termios(tty, &tmp_termios);		if (!(tmp_termios.c_cflag & CRTSCTS))			pr_warn("speakup: Failed to set hardware flow control/n");	}	tty_unlock(tty);	ret = tty_set_ldisc(tty, N_SPEAKUP);	if (ret)		pr_err("speakup: Failed to set N_SPEAKUP on tty/n");	return ret;}
开发者ID:mkrufky,项目名称:linux,代码行数:48,


示例6: ptmx_open

static int ptmx_open(struct inode *inode, struct file *filp){	struct tty_struct *tty;	int retval;	int index;	nonseekable_open(inode, filp);	/* find a device that is not in use. */	tty_lock();	index = devpts_new_index(inode);	tty_unlock();	if (index < 0)		return index;	mutex_lock(&tty_mutex);	tty_lock();	tty = tty_init_dev(ptm_driver, index, 1);	mutex_unlock(&tty_mutex);	if (IS_ERR(tty)) {		retval = PTR_ERR(tty);		goto out;	}	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */	tty_add_file(tty, filp);	retval = devpts_pty_new(inode, tty->link);	if (retval)		goto out1;	retval = ptm_driver->ops->open(tty, filp);	if (retval)		goto out2;out1:	tty_unlock();	return retval;out2:	tty_unlock();	tty_release(inode, filp);	return retval;out:	devpts_kill_index(inode, index);	tty_unlock();	return retval;}
开发者ID:patrick-ken,项目名称:MyNet_N900,代码行数:48,


示例7: kmioctl

int kmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, proc_t p){    int error = 0;    struct tty *tp = km_tty[minor(dev)];    struct winsize *wp;    tty_lock(tp);    switch (cmd) {    case KMIOCSIZE:        wp = (struct winsize *) data;        *wp = tp->t_winsize;        break;    case TIOCSWINSZ:        /*         * Prevent changing of console size --         * * this ensures that login doesn't revert to the         * * termcap-defined size         */        error = EINVAL;        break;        /*         * Bodge in the CLOCAL flag as the km device is always local          */    case TIOCSETA_32:    case TIOCSETAW_32:    case TIOCSETAF_32:        {            struct termios32 *t = (struct termios32 *) data;            t->c_cflag |= CLOCAL;            /*             * No Break              */        }        goto fallthrough;    case TIOCSETA_64:    case TIOCSETAW_64:    case TIOCSETAF_64:        {            struct user_termios *t = (struct user_termios *) data;            t->c_cflag |= CLOCAL;            /*             * No Break              */        } fallthrough:    default:        error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, p);        if (ENOTTY != error)            break;        error = ttioctl_locked(tp, cmd, data, flag, p);        break;    }    tty_unlock(tp);    return (error);}
开发者ID:DINKIN,项目名称:xnu,代码行数:60,


示例8: tty_ldisc_release

void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty){	/*	 * Prevent flush_to_ldisc() from rescheduling the work for later.  Then	 * kill any delayed work. As this is the final close it does not	 * race with the set_ldisc code path.	 */	tty_unlock();	tty_ldisc_halt(tty);	tty_ldisc_flush_works(tty);	tty_lock();	mutex_lock(&tty->ldisc_mutex);	/*	 * Now kill off the ldisc	 */	tty_ldisc_close(tty, tty->ldisc);	tty_ldisc_put(tty->ldisc);	/* Force an oops if we mess this up */	tty->ldisc = NULL;	/* Ensure the next open requests the N_TTY ldisc */	tty_set_termios_ldisc(tty, N_TTY);	mutex_unlock(&tty->ldisc_mutex);	/* This will need doing differently if we need to lock */	if (o_tty)		tty_ldisc_release(o_tty, NULL);	/* And the memory resources remaining (buffers, termios) will be	   disposed of when the kref hits zero */}
开发者ID:macbury,项目名称:linux-2.6,代码行数:33,


示例9: ptsdev_kqfilter

static intptsdev_kqfilter(struct file *fp, struct knote *kn){	struct tty *tp = fp->f_data;	struct pts_softc *psc = tty_softc(tp);	int error = 0;	tty_lock(tp);	switch (kn->kn_filter) {	case EVFILT_READ:		kn->kn_fop = &pts_kqops_read;		knlist_add(&psc->pts_outpoll.si_note, kn, 1);		break;	case EVFILT_WRITE:		kn->kn_fop = &pts_kqops_write;		knlist_add(&psc->pts_inpoll.si_note, kn, 1);		break;	default:		error = EINVAL;		break;	}	tty_unlock(tp);	return (error);}
开发者ID:JasonFord53,项目名称:freebsd,代码行数:26,


示例10: xencons_rx

void xencons_rx(char *buf, unsigned len){	int           i;	struct tty *tp = xccons;	if (xen_console_up#ifdef DDB	    && !kdb_active#endif		) {		tty_lock(tp);		for (i = 0; i < len; i++) {#ifdef KDB			kdb_alt_break(buf[i], &xc_altbrk);#endif			ttydisc_rint(tp, buf[i], 0);		}		ttydisc_rint_done(tp);		tty_unlock(tp);	} else {		CN_LOCK(cn_mtx);		for (i = 0; i < len; i++)			rbuf[RBUF_MASK(rp++)] = buf[i];		CN_UNLOCK(cn_mtx);	}}
开发者ID:Alkzndr,项目名称:freebsd,代码行数:27,


示例11: pty_close

static void pty_close(struct tty_struct *tty, struct file *filp){	BUG_ON(!tty);	if (tty->driver->subtype == PTY_TYPE_MASTER)		WARN_ON(tty->count > 1);	else {		if (tty->count > 2)			return;	}	wake_up_interruptible(&tty->read_wait);	wake_up_interruptible(&tty->write_wait);	tty->packet = 0;	if (!tty->link)		return;	set_bit(TTY_OTHER_CLOSED, &tty->link->flags);	wake_up_interruptible(&tty->link->read_wait);	wake_up_interruptible(&tty->link->write_wait);	if (tty->driver->subtype == PTY_TYPE_MASTER) {		set_bit(TTY_OTHER_CLOSED, &tty->flags);#ifdef CONFIG_UNIX98_PTYS		if (tty->driver == ptm_driver)			devpts_pty_kill(tty->link);#endif		tty_unlock();		tty_vhangup(tty->link);		tty_lock();	}}
开发者ID:GREYFOXRGR,项目名称:BPI-M3-bsp,代码行数:28,


示例12: cons_cinput

/* * cons_cinput * * Driver character input from the polled mode serial console driver calls * this routine to input a character from the serial driver into the tty * line discipline specific input processing receiv interrupt routine, * l_rint(). * * Locks:       Assumes that the tty_lock() is NOT held on the tp, so a *              serial driver should NOT call this function as a result *              of being called from a function which already holds the *              lock; ECHOE will be handled at the line discipline, if *              output echo processing is going to occur. */void cons_cinput(char ch){    struct tty *tp = km_tty[0]; /* XXX */    tty_lock(tp);    (*linesw[tp->t_line].l_rint) (ch, tp);    tty_unlock(tp);}
开发者ID:DINKIN,项目名称:xnu,代码行数:22,


示例13: kmtimeout

/*  * One-shot output retry timeout from kmoutput(); re-calls kmoutput() at * intervals until the output queue for the tty is empty, at which point * the timeout is not rescheduled by kmoutput() *  * This function must take the tty_lock() around the kmoutput() call; it * ignores the return value. */static void kmtimeout(void *arg){    struct tty *tp = (struct tty *) arg;    tty_lock(tp);    (void) kmoutput(tp);    tty_unlock(tp);}
开发者ID:DINKIN,项目名称:xnu,代码行数:16,


示例14: bvm_tty_close

static voidbvm_tty_close(struct tty *tp){	tty_lock(tp);	callout_stop(&bvm_timer);	tty_unlock(tp);}
开发者ID:Zer0day,项目名称:freebsd,代码行数:8,


示例15: tty_ldisc_change

/** *	tty_ldisc_change	-	change line discipline *	@tty: tty to change *	@disc: new line discipine number * *	Change the line discipline of the tty. The tty must have an old *	ldisc attached to, we must handle it properly. Sandix implement *	it quite simple, but please look at linux, see how complex it is! *	XXX tty shoud be locked */int tty_ldisc_change(struct tty_struct *tty, int disc){	int ret;	struct tty_ldisc *old_ldisc, *new_ldisc;	BUG_ON(!tty->ldisc);	if (tty->ldisc->ops->num == disc)		return 0;	tty_lock(tty);	new_ldisc = tty_ldisc_get(tty, disc);	if (IS_ERR(new_ldisc)) {		tty_unlock(tty);		return PTR_ERR(new_ldisc);	}	old_ldisc = tty->ldisc;	/* Close the old one */	tty_ldisc_close(tty, old_ldisc);	/* Set up the new one */	tty->ldisc = new_ldisc;	tty_set_termios_ldisc(tty, disc);	ret = tty_ldisc_open(tty, new_ldisc);	if (ret) {		/* Back to the old one or N_TTY */		tty_ldisc_put(new_ldisc);		tty_ldisc_restore(tty, old_ldisc);	}	/*	 * At this point we hold a reference to the new ldisc and a	 * reference to the old ldisc, or we hold two references to	 * the old ldisc (if it was restored as part of error cleanup	 * above). In either case, releasing a single reference from	 * the old ldisc is correct.	 */	tty_ldisc_put(old_ldisc);	tty_unlock(tty);	return ret;}
开发者ID:lastweek,项目名称:Sandix,代码行数:54,


示例16: r3964_write

static ssize_t r3964_write(struct tty_struct *tty, struct file *file,			   const unsigned char *data, size_t count){	struct r3964_info *pInfo = tty->disc_data;	struct r3964_block_header *pHeader;	struct r3964_client_info *pClient;	unsigned char *new_data;	TRACE_L("write request, %d characters", count);	if (!pInfo)		return -EIO;	if (count > R3964_MTU) {		if (pInfo->flags & R3964_DEBUG) {			TRACE_L(KERN_WARNING "r3964_write: truncating user "				"packet from %u to mtu %d", count, R3964_MTU);		}		count = R3964_MTU;	}	new_data = kmalloc(count + sizeof(struct r3964_block_header),			GFP_KERNEL);	TRACE_M("r3964_write - kmalloc %p", new_data);	if (new_data == NULL) {		if (pInfo->flags & R3964_DEBUG) {			printk(KERN_ERR "r3964_write: no memory/n");		}		return -ENOSPC;	}	pHeader = (struct r3964_block_header *)new_data;	pHeader->data = new_data + sizeof(struct r3964_block_header);	pHeader->length = count;	pHeader->locks = 0;	pHeader->owner = NULL;	tty_lock();	pClient = findClient(pInfo, task_pid(current));	if (pClient) {		pHeader->owner = pClient;	}	memcpy(pHeader->data, data, count);		if (pInfo->flags & R3964_DEBUG) {		dump_block(pHeader->data, count);	}	add_tx_queue(pInfo, pHeader);	trigger_transmit(pInfo);	tty_unlock();	return 0;}
开发者ID:DirtyDroidX,项目名称:android_kernel_htc_m8ul,代码行数:56,


示例17: r3964_read

static ssize_t r3964_read(struct tty_struct *tty, struct file *file,			  unsigned char __user * buf, size_t nr){	struct r3964_info *pInfo = tty->disc_data;	struct r3964_client_info *pClient;	struct r3964_message *pMsg;	struct r3964_client_message theMsg;	int ret;	TRACE_L("read()");	tty_lock();	pClient = findClient(pInfo, task_pid(current));	if (pClient) {		pMsg = remove_msg(pInfo, pClient);		if (pMsg == NULL) {			/* no messages available. */			if (file->f_flags & O_NONBLOCK) {				ret = -EAGAIN;				goto unlock;			}			/* block until there is a message: */			wait_event_interruptible_tty(pInfo->read_wait,					(pMsg = remove_msg(pInfo, pClient)));		}		/* If we still haven't got a message, we must have been signalled */		if (!pMsg) {			ret = -EINTR;			goto unlock;		}		/* deliver msg to client process: */		theMsg.msg_id = pMsg->msg_id;		theMsg.arg = pMsg->arg;		theMsg.error_code = pMsg->error_code;		ret = sizeof(struct r3964_client_message);		kfree(pMsg);		TRACE_M("r3964_read - msg kfree %p", pMsg);		if (copy_to_user(buf, &theMsg, ret)) {			ret = -EFAULT;			goto unlock;		}		TRACE_PS("read - return %d", ret);		goto unlock;	}	ret = -EPERM;unlock:	tty_unlock();	return ret;}
开发者ID:aywq2008,项目名称:omniplay,代码行数:56,


示例18: kmwrite

int kmwrite(dev_t dev, struct uio *uio, int ioflag){    int ret;    struct tty *tp = km_tty[minor(dev)];    tty_lock(tp);    ret = (*linesw[tp->t_line].l_write) (tp, uio, ioflag);    tty_unlock(tp);    return (ret);}
开发者ID:DINKIN,项目名称:xnu,代码行数:11,


示例19: tty_close

int tty_close(){	if(!tty_port) return ME_CLOSE;	DEBUG(('M',2,"tty_close"));	fflush(stdin);fflush(stdout);	tty_cooked();	fclose(stdin);fclose(stdout);	tty_unlock(tty_port);	xfree(tty_port);	return ME_OK;}
开发者ID:sisoftrg,项目名称:qico,代码行数:11,


示例20: uart_tty_intr

voiduart_tty_intr(void *arg){	struct uart_softc *sc = arg;	struct tty *tp;	int c, err = 0, pend, sig, xc;	if (sc->sc_leaving)		return;	pend = atomic_readandclear_32(&sc->sc_ttypend);	if (!(pend & SER_INT_MASK))		return;	tp = sc->sc_u.u_tty.tp;	tty_lock(tp);	if (pend & SER_INT_RXREADY) {		while (!uart_rx_empty(sc) && !sc->sc_isquelch) {			xc = uart_rx_peek(sc);			c = xc & 0xff;			if (xc & UART_STAT_FRAMERR)				err |= TRE_FRAMING;			if (xc & UART_STAT_OVERRUN)				err |= TRE_OVERRUN;			if (xc & UART_STAT_PARERR)				err |= TRE_PARITY;			if (ttydisc_rint(tp, c, err) != 0) {				sc->sc_isquelch = 1;				if ((tp->t_termios.c_cflag & CRTS_IFLOW) &&				    !sc->sc_hwiflow)					UART_SETSIG(sc, SER_DRTS);			} else				uart_rx_next(sc);		}	}	if (pend & SER_INT_BREAK)		ttydisc_rint(tp, 0, TRE_BREAK);	if (pend & SER_INT_SIGCHG) {		sig = pend & SER_INT_SIGMASK;		if (sig & SER_DDCD)			ttydisc_modem(tp, sig & SER_DCD);		if (sig & SER_DCTS)			uart_tty_outwakeup(tp);	}	if (pend & SER_INT_TXIDLE)		uart_tty_outwakeup(tp);	ttydisc_rint_done(tp);	tty_unlock(tp);}
开发者ID:AhmadTux,项目名称:freebsd,代码行数:53,


示例21: kmclose

int kmclose(dev_t dev, int flag, __unused int mode, __unused proc_t p){    int ret;    struct tty *tp = km_tty[minor(dev)];    tty_lock(tp);    ret = (*linesw[tp->t_line].l_close) (tp, flag);    ttyclose(tp);    tty_unlock(tp);    return (ret);}
开发者ID:DINKIN,项目名称:xnu,代码行数:12,


示例22: mambo_timeout

static voidmambo_timeout(void *v){	int 	c;	tty_lock(tp);	while ((c = mambo_cngetc(NULL)) != -1)		ttydisc_rint(tp, c, 0);	ttydisc_rint_done(tp);	tty_unlock(tp);	callout_reset(&mambo_callout, polltime, mambo_timeout, NULL);}
开发者ID:edgar-pek,项目名称:PerspicuOS,代码行数:13,


示例23: spk_ttyio_release

void spk_ttyio_release(void){	if (!speakup_tty)		return;	tty_lock(speakup_tty);	if (speakup_tty->ops->close)		speakup_tty->ops->close(speakup_tty, NULL);	tty_ldisc_flush(speakup_tty);	tty_unlock(speakup_tty);	tty_kclose(speakup_tty);}
开发者ID:mkrufky,项目名称:linux,代码行数:14,


示例24: bvm_timeout

static voidbvm_timeout(void *v){	struct	tty *tp;	int 	c;	tp = (struct tty *)v;	tty_lock(tp);	while ((c = bvm_cngetc(NULL)) != -1)		ttydisc_rint(tp, c, 0);	ttydisc_rint_done(tp);	tty_unlock(tp);	bvm_timeouthandle = timeout(bvm_timeout, tp, polltime);}
开发者ID:coyizumi,项目名称:cs111,代码行数:16,


示例25: get_serial_info

static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss){	struct serial_state *state = tty->driver_data;	tty_lock(tty);	ss->line = tty->index;	ss->port = state->port;	ss->flags = state->tport.flags;	ss->xmit_fifo_size = state->xmit_fifo_size;	ss->baud_base = state->baud_base;	ss->close_delay = state->tport.close_delay;	ss->closing_wait = state->tport.closing_wait;	ss->custom_divisor = state->custom_divisor;	tty_unlock(tty);	return 0;}
开发者ID:AlexShiLucky,项目名称:linux,代码行数:16,



注:本文中的tty_unlock函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。


C++ tty_unregister_device函数代码示例
C++ tty_termios_encode_baud_rate函数代码示例
万事OK自学网:51自学网_软件自学网_CAD自学网自学excel、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。