9os

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit ad5b0eca116e3da5049a37627402b2ee363e5985
parent d03a32a2cbe192dbf7bbf098ce2227d97d156390
Author: Roberto E. Vargas Caballero <roberto.vargas@midokura.com>
Date:   Tue, 22 Nov 2022 19:25:24 +0100

os9: Refcount channels when cloning fds

Channels can be shared between different fds and we cannot free
a channel without ref counting it usage.

Diffstat:
Minclude/os9/os9.h | 1+
Msrc/os9/dev/dev.c | 31+++++++++++++++++++++++++++++--
2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/include/os9/os9.h b/include/os9/os9.h @@ -153,6 +153,7 @@ struct dir { }; struct chan { + Ref ref; long offset; int index; Qid qid; diff --git a/src/os9/dev/dev.c b/src/os9/dev/dev.c @@ -43,6 +43,7 @@ newchan(unsigned char type) if ((c = allocchan()) == NULL) goto err2; memset(c, 0, sizeof(*c)); + initref(&c->ref); c->type = type; lock(&c->mutex); @@ -75,14 +76,26 @@ newspace(Nspace *from) Fdset * newfds(Fdset *from) { + int i; + Chan *c; Fdset *fds; if ((fds = allocfds()) == NULL) return NULL; - - *fds = (from) ? *from : (Fdset) {0}; + memset(fds, 0, sizeof(*fds)); initref(&fds->ref); + if (!from) + return fds; + + lock(&from->m); + for (i = 0; i < NR_CHANS; ++i) { + c = fds->fdset[i] = from->fdset[i]; + if (c) + incref(&c->ref); + } + unlock(&from->m); + return fds; } @@ -97,8 +110,19 @@ delspace(Nspace *ns) void delfds(Fdset *fds) { + int i; + Chan *c; + if (!decref(&fds->ref)) return; + + for (i = 0; i < NR_CHANS; ++i) { + c = fds->fdset[i]; + if (!c) + continue; + lock(&c->mutex); + devclose(c); + } freefds(fds); } @@ -108,6 +132,9 @@ delchan(Chan *c) Chan **bp; Fdset *fds = proc->fds; + if (!decref(&c->ref)) + return; + lock(&fds->m); for (bp = fds->fdset; bp < &fds->fdset[NR_CHANS]; ++bp) { if (*bp == c)