On Sunday 22 May 2005 18:06, Scott Long wrote: > > > > When I worked with USB I ran into some synchronization problems with > > callbacks that leaded me to writing to the stack of another thread, which > > I hope is OK. > > No, it's not ok. Kernel stacks can be swapped out while sleeping. > Writing to a swapped out stack will cause a VM panic.
OK, maybe I have to create a bitmap in "struct thread" where I can store that information, though that will limit the maximum number of context exits to a constant. And then change things a little bit. I assume that "curthread" points to the currently active thread and is always set? But the principle will be exactly the same. Please read through my previous e-mail and the function below again! #define CONTEXT_MAX (8*8) struct thread { ... u_int8_t context_index; u_int8_t context_bitmap[(CONTEXT_MAX+7)/8]; ... }; struct context { struct mtx *mtx; u_int8_t *done_p; u_int8_t done_index; }; void callback_thread(): { retry: #define max_callback 16 #if (max_callback >= CONTEXT_MAX) #error "out of contexts" #endif struct callback * callbacks[max_callback]; struct mtx * mtxs[max_callback]; int x = 0; int repeat = 0; int retry = 0; u_int8_t index = curthread->context_index; if(index >= (CONTEXT_MAX - max_callback)) { panic("out of contexts\n"); } mtx_lock(&global_callback_lock); while(1) { callbacks[x] = GET_NEXT_CALLBACK(); if(callbacks[x] == NULL) { break; } if(callbacks[x]->ctx.done_p) { /* another thread is calling callback * ERROR */ continue; } /* clear bit */ curthread->context_bitmap[index / 8] &= ~(1 << (index % 8)); callbacks[x]->ctx.done_p = &curthread->context_bitmap[0]; callbacks[x]->ctx.done_index = index; mtxs[x] = callbacks[x]->ctx.mtx; x++; index++; if(x == max_callback) { retry = 1; break; } } curthread->context_index = index; mtx_unlock(&global_callback_lock); /* here one needs to switch lock to avoid * locking order reversal */ while(x--) { /* do you see the point in storing a pointer to the * mutex on the stack ? * The callback structure might have been freed when one * gets here and needs a copy ! */ mtx_lock(mtxs[x]); /* do you see the point in checking the bit below? * It is supposed to get set if this callback has been * stopped during the lock switch! */ if(!(curthread->context_bitmap[index / 8] & (1<<(index % 8)))) { callbacks[x]->ctx.done_p = NULL; (callbacks[x]->func)(callbacks[x]->arg, &callback[x]->ctx); } /* else callback stopped */ mtx_unlock(mtxs[x]); /* free up bits used */ index--; curthread->context_index--; } if(retry) { retry = 0; goto retry; } } > > > What do you think about the following: > > [...] > > > I hope this wasn't too much for you to read :-) > > > > Any comments ? > > > > I'm not too familiar with the exact problem you're trying to solve in > USB. I guess you need to be able to allocate a contiguous chunk of > memory in order to do a transaction, but are afraid that state will > change while the allocation is in progress? > That's one problem. > What is the maximum size > of memory that the hardware can handle for this transaction? It is limited to the amount of available memory. > How many transactions can be handled concurrently by the hardware? Typically there is more than one transaction i parallell, and there is synchronous transfers waiting for completion and non-synchronous transfers not waiting for completion, that call callbacks. > What state are you trying to protect? For example that the callback is not called after that I have stopped a non-synchronous transfer. > Is it possible to do the allocation before > the state needs to be protected? Mostly, but not always, though that only solves one part of the problem. --HPS _______________________________________________ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "[EMAIL PROTECTED]"