unlock(r);
if(x < 0)
panic("decref pc=%#p", getcallerpc(&r));
-
return x;
}
int nt;
nt = strlen(t);
- if(nt+1 <= ns){
- memmove(s, t, nt+1);
- return;
- }
- /* too long */
- if(ns < 4){
- /* but very short! */
- strncpy(s, t, ns);
+ if(nt < ns){
+ memmove(s, t, nt);
+ s[nt] = '\0';
return;
}
- /* truncate with ... at character boundary (very rare case) */
- memmove(s, t, ns-4);
+ /* too long, truncate */
+ nt = ns-1;
+ memmove(s, t, nt);
+ s[nt] = '\0';
+ /* append ... if there is space */
ns -= 4;
- s[ns] = '\0';
+ if(ns < 0)
+ return;
/* look for first byte of UTF-8 sequence by skipping continuation bytes */
while(ns>0 && (s[--ns]&0xC0)==0x80)
;
int n;
char *t, *prev;
- n = strlen(s)+1;
+ n = strlen(s);
/* if it's a user, we can wait for memory; if not, something's very wrong */
- if(up){
- t = smalloc(n);
- setmalloctag(t, getcallerpc(&p));
- }else{
- t = malloc(n);
+ if(up != nil)
+ t = smalloc(n+1);
+ else{
+ t = malloc(n+1);
if(t == nil)
panic("kstrdup: no memory");
}
+ setmalloctag(t, getcallerpc(&p));
memmove(t, s, n);
+ t[n] = '\0';
prev = *p;
*p = t;
free(prev);
devtab[i]->reset();
}
+static void closeproc(void*);
+
void
chandevinit(void)
{
for(i=0; devtab[i] != nil; i++)
devtab[i]->init();
+ kproc("closeproc", closeproc, nil);
}
void
struct {
Chan *head;
Chan *tail;
- int nqueued;
- int nclosed;
+ ulong nqueued;
+ ulong nclosed;
Lock l;
QLock q;
Rendez r;
}
static void
-closeproc(void*)
+closechanq(Chan *c)
+{
+ lock(&clunkq.l);
+ clunkq.nqueued++;
+ c->next = nil;
+ if(clunkq.head)
+ clunkq.tail->next = c;
+ else
+ clunkq.head = c;
+ clunkq.tail = c;
+ unlock(&clunkq.l);
+ wakeup(&clunkq.r);
+}
+
+static Chan*
+closechandeq(void)
+{
+ Chan *c;
+
+ lock(&clunkq.l);
+ c = clunkq.head;
+ if(c != nil) {
+ clunkq.head = c->next;
+ clunkq.nclosed++;
+ }
+ unlock(&clunkq.l);
+ return c;
+}
+
+static void
+closeproc(void *)
{
Chan *c;
for(;;){
- if(clunkq.head == nil){
- if(!waserror()){
- tsleep(&clunkq.r, clunkwork, nil, 5000);
+ c = closechandeq();
+ if(c == nil) {
+ qlock(&clunkq.q);
+ if(!waserror()) {
+ tsleep(&clunkq.r, clunkwork, nil, 500);
poperror();
}
+ c = closechandeq();
+ if(c == nil) {
+ if(clunkq.q.head != nil) {
+ qunlock(&clunkq.q);
+ pexit("no work", 1);
+ }
+ qunlock(&clunkq.q);
+ continue;
+ }
+ if(clunkq.q.head == nil) {
+ if(!waserror()) {
+ kproc("closeproc", closeproc, nil);
+ poperror();
+ }
+ }
+ qunlock(&clunkq.q);
}
- qunlock(&clunkq.q);
- lock(&clunkq.l);
- c = clunkq.head;
- if(c == nil){
- unlock(&clunkq.l);
- pexit("no work", 1);
- }
- clunkq.head = c->next;
- clunkq.nclosed++;
- unlock(&clunkq.l);
if(!waserror()){
devtab[c->type]->close(c);
poperror();
}
chanfree(c);
- qlock(&clunkq.q);
}
}
-static void
-closechanq(Chan *c)
-{
- lock(&clunkq.l);
- clunkq.nqueued++;
- c->next = nil;
- if(clunkq.head)
- clunkq.tail->next = c;
- else
- clunkq.head = c;
- clunkq.tail = c;
- unlock(&clunkq.l);
-
- if(up != 0 && palloc.Lock.p != up && canqlock(&clunkq.q)){
- c = up->dot;
- up->dot = nil;
- kproc("closeproc", closeproc, nil);
- up->dot = c;
- }else
- wakeup(&clunkq.r);
-}
-
void
cclose(Chan *c)
{
if(devtab[c->type]->dc == L'M')
if((c->flag&(CRCLOSE|CCACHE)) == CCACHE)
- if((c->qid.type&(QTEXCL|QTMOUNT|QTAUTH)) == 0){
+ if((c->qid.type&(QTEXCL|QTMOUNT|QTAUTH)) == 0)
+ if((clunkq.nqueued - clunkq.nclosed) < 64){
closechanq(c);
return;
}
*nerror = nhave;
pathclose(path);
cclose(c);
- strcpy(up->errstr, Enotdir);
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
if(mh != nil)
putmhead(mh);
return -1;
if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
if(nerror)
*nerror = nhave+wq->nqid+1;
- strcpy(up->errstr, Edoesnotexist);
+ kstrcpy(up->errstr, Edoesnotexist, ERRMAX);
}else{
if(nerror)
*nerror = nhave+wq->nqid;
- strcpy(up->errstr, Enotdir);
+ kstrcpy(up->errstr, Enotdir, ERRMAX);
}
free(wq);
if(mh != nil)
nexterror();
}
for(f = m->mount; f; f = f->next){
- if(f->mflag&MCREATE){
+ if(f->to != nil && (f->mflag&MCREATE) != 0){
nc = cclone(f->to);
runlock(&m->lock);
poperror();
/* save&update the name; domount might change c */
path = c->path;
incref(path);
+ if(waserror()){
+ pathclose(path);
+ nexterror();
+ }
m = nil;
if(!nomount)
domount(&c, &m, &path);
/* now it's our copy anyway, we can put the name back */
pathclose(c->path);
c->path = path;
+ poperror();
/* record whether c is on a mount point */
c->ismtpt = m!=nil;