problems with new the "contigmalloc" routine
Hans Petter Selasky
hselasky at c2i.net
Sun May 22 18:10:09 GMT 2005
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
More information about the freebsd-hackers
mailing list