summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/bthread.c3
-rw-r--r--common/bthread.c44
-rw-r--r--drivers/usb/gadget/f_mass_storage.c51
-rw-r--r--include/bthread.h2
4 files changed, 56 insertions, 44 deletions
diff --git a/commands/bthread.c b/commands/bthread.c
index 446fe9c37a..ce3db2d3d2 100644
--- a/commands/bthread.c
+++ b/commands/bthread.c
@@ -61,7 +61,6 @@ static int bthread_isolated_time(void)
}
__bthread_stop(bthread);
- bthread_free(bthread);
return i;
}
@@ -120,7 +119,6 @@ cleanup:
while (i--) {
arg = bthread_data(bthread[i]);
__bthread_stop(bthread[i]);
- bthread_free(bthread[i]);
if (!ret && (arg->out != 4 || yields < arg->out))
ret = -EIO;
@@ -184,7 +182,6 @@ cleanup:
list_for_each_entry_safe(spawner, tmp, &spawners, list) {
arg = bthread_data(spawner->bthread);
__bthread_stop(spawner->bthread);
- bthread_free(spawner->bthread);
if (!ret && arg->out)
ret = arg->out;
free(arg);
diff --git a/common/bthread.c b/common/bthread.c
index 48248dfad4..46e6987149 100644
--- a/common/bthread.c
+++ b/common/bthread.c
@@ -32,10 +32,12 @@ static struct bthread {
#endif
u8 awake :1;
u8 should_stop :1;
+ u8 should_clean :1;
u8 has_stopped :1;
} main_thread = {
.list = LIST_HEAD_INIT(main_thread.list),
.name = "main",
+ .awake = true,
};
struct bthread *current = &main_thread;
@@ -66,7 +68,7 @@ bool bthread_is_main(struct bthread *bthread)
return bthread == &main_thread;
}
-void bthread_free(struct bthread *bthread)
+static void bthread_free(struct bthread *bthread)
{
free(bthread->stack);
free(bthread->name);
@@ -104,6 +106,8 @@ struct bthread *bthread_create(void (*threadfn)(void *), void *data,
if (len < 0)
goto err;
+ list_add_tail(&bthread->list, &current->list);
+
/* set up bthread context with the new stack */
initjmp(bthread->jmp_buf, bthread_trampoline,
bthread->stack + CONFIG_STACK_SIZE);
@@ -121,26 +125,31 @@ void *bthread_data(struct bthread *bthread)
void bthread_wake(struct bthread *bthread)
{
- if (bthread->awake)
- return;
- list_add_tail(&bthread->list, &current->list);
bthread->awake = true;
}
void bthread_suspend(struct bthread *bthread)
{
- if (!bthread->awake)
- return;
bthread->awake = false;
- list_del(&bthread->list);
+}
+
+void bthread_cancel(struct bthread *bthread)
+{
+ bthread->should_stop = true;
+ bthread->should_clean = true;
}
void __bthread_stop(struct bthread *bthread)
{
bthread->should_stop = true;
+ pr_debug("waiting for %s to stop\n", bthread->name);
+
while (!bthread->has_stopped)
bthread_reschedule();
+
+ list_del(&bthread->list);
+ bthread_free(bthread);
}
int bthread_should_stop(void)
@@ -163,10 +172,23 @@ void bthread_info(void)
void bthread_reschedule(void)
{
- struct bthread *next = list_next_entry(current, list);
- if (current != next)
- pr_debug("switch %s -> %s\n", current->name, next->name);
- bthread_schedule(next);
+ struct bthread *next, *tmp;
+
+ if (current == list_next_entry(current, list))
+ return;
+
+ list_for_each_entry_safe(next, tmp, &current->list, list) {
+ if (next->awake) {
+ pr_debug("switch %s -> %s\n", current->name, next->name);
+ bthread_schedule(next);
+ return;
+ }
+ if (next->has_stopped && next->should_clean) {
+ pr_debug("deleting %s\n", next->name);
+ list_del(&next->list);
+ bthread_free(next);
+ }
+ }
}
void bthread_schedule(struct bthread *to)
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 0033a95f68..753042125d 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -2335,9 +2335,12 @@ static void handle_exception(struct fsg_common *common)
/*-------------------------------------------------------------------------*/
-static void fsg_main_thread(void *common_)
+static void fsg_main_thread(void *fsg_)
{
- struct fsg_common *common = common_;
+ struct fsg_dev *fsg = fsg_;
+ struct fsg_common *common = fsg->common;
+ struct fsg_buffhd *bh;
+ unsigned i;
int ret = 0;
/* The main loop */
@@ -2376,6 +2379,21 @@ static void fsg_main_thread(void *common_)
if (ret && ret != -ERESTARTSYS)
pr_warn("%s: error %pe\n", __func__, ERR_PTR(ret));
+
+ usb_free_all_descriptors(&fsg->function);
+
+ for (i = 0; i < ums_count; i++)
+ close(ums[i].fd);
+
+ bh = common->buffhds;
+ i = FSG_NUM_BUFFERS;
+
+ do {
+ dma_free(bh->buf);
+ } while (++bh, --i);
+
+ ums_count = 0;
+ ums_files = NULL;
}
static void fsg_common_release(struct fsg_common *common);
@@ -2409,7 +2427,7 @@ static int fsg_common_init(struct fsg_common *common,
common->ep0 = gadget->ep0;
common->ep0req = cdev->req;
- thread_task = bthread_run(fsg_main_thread, common, "mass-storage-gadget");
+ thread_task = bthread_run(fsg_main_thread, common->fsg, "mass-storage-gadget");
if (IS_ERR(thread_task))
return PTR_ERR(thread_task);
@@ -2531,52 +2549,27 @@ close:
static void fsg_common_release(struct fsg_common *common)
{
- struct fsg_buffhd *bh;
- unsigned i;
-
/* If the thread isn't already dead, tell it to exit now */
if (common->state != FSG_STATE_TERMINATED) {
raise_exception(common, FSG_STATE_EXIT);
- __bthread_stop(thread_task);
- bthread_free(thread_task);
}
- bh = common->buffhds;
- i = FSG_NUM_BUFFERS;
-
- do {
- dma_free(bh->buf);
- } while (++bh, --i);
-
- ums_count = 0;
+ bthread_cancel(thread_task);
}
static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
- struct fsg_common *common = fsg->common;
- int i;
DBG(fsg, "unbind\n");
if (fsg->common->fsg == fsg) {
fsg->common->new_fsg = NULL;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
-
- __bthread_stop(thread_task);
- while (common->fsg == fsg)
- bthread_reschedule();
}
- usb_free_all_descriptors(&fsg->function);
-
- for (i = 0; i < ums_count; i++)
- close(ums[i].fd);
-
fsg_common_release(fsg->common);
-
- ums_files = NULL;
}
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
diff --git a/include/bthread.h b/include/bthread.h
index 407aa830a8..4441b53696 100644
--- a/include/bthread.h
+++ b/include/bthread.h
@@ -13,7 +13,7 @@ struct bthread;
extern struct bthread *current;
struct bthread *bthread_create(void (*threadfn)(void *), void *data, const char *namefmt, ...);
-void bthread_free(struct bthread *bthread);
+void bthread_cancel(struct bthread *bthread);
void bthread_schedule(struct bthread *);
void bthread_wake(struct bthread *bthread);