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