Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.arch.embedded > #24329 > unrolled thread
| Started by | Tim Wescott <seemywebsite@myfooter.really> |
|---|---|
| First post | 2016-06-24 13:37 -0500 |
| Last post | 2016-07-14 20:44 +0000 |
| Articles | 20 on this page of 196 — 27 participants |
Back to article view | Back to comp.arch.embedded
Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-06-24 13:37 -0500
Re: Common name for a "Task Loop" Lanarcam <lanarcam1@yahoo.fr> - 2016-06-24 21:04 +0200
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-24 15:21 -0500
Re: Common name for a "Task Loop" Tauno Voipio <tauno.voipio@notused.fi.invalid> - 2016-06-24 22:46 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-24 14:51 -0500
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-24 15:10 -0500
Re: Common name for a "Task Loop" Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-06-24 20:11 +0000
Re: Common name for a "Task Loop" gtwrek@sonic.net (Mark Curry) - 2016-06-24 20:31 +0000
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-24 13:21 -0700
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-24 18:31 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-24 17:03 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-25 10:52 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 01:07 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-25 14:00 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 08:27 -0700
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-25 15:50 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 14:45 -0700
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-06-25 17:28 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 00:40 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-26 12:41 +0300
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-25 15:46 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 14:42 -0700
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-25 15:43 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 14:36 -0700
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-06-25 17:25 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 00:14 -0700
Re: Common name for a "Task Loop" Paul Rubin <no.email@nospam.invalid> - 2016-06-24 14:00 -0700
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-06-25 15:27 +0000
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 09:41 -0700
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-06-25 17:59 +0000
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-06-25 16:24 -0500
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-06-26 23:36 +0000
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-06-26 19:00 -0500
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-27 05:53 +0300
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-27 09:43 -0500
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-06-28 02:39 +0000
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 15:08 -0700
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-06-26 23:54 +0000
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 18:12 -0700
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-06-28 02:54 +0000
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-28 06:20 +0300
Re: Common name for a "Task Loop" raimond.dragomir@gmail.com - 2016-06-27 22:57 -0700
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-28 09:40 -0500
Re: Common name for a "Task Loop" Mel Wilson <mwilson@the-wire.com> - 2016-06-28 15:38 +0000
Re: Common name for a "Task Loop" raimond.dragomir@gmail.com - 2016-06-28 08:57 -0700
Re: Common name for a "Task Loop" Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-06-28 16:49 +0000
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-28 15:35 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 13:54 -0700
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 14:04 -0700
Re: Common name for a "Task Loop" Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-06-28 21:09 +0000
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 15:14 -0700
Re: Common name for a "Task Loop" Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-06-28 22:30 +0000
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 16:06 -0700
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 16:18 -0700
Re: Common name for a "Task Loop" Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2016-06-29 01:32 +0200
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-29 01:00 +0300
Re: Common name for a "Task Loop" Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2016-06-29 00:20 +0200
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-29 02:07 +0300
Re: Common name for a "Task Loop" Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-06-28 22:21 +0000
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-29 02:20 +0300
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-06-28 17:39 -0500
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-29 02:29 +0300
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-29 09:50 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 15:43 -0700
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-29 02:40 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 16:56 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-29 08:04 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 23:22 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-30 09:02 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-30 02:33 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-02 14:27 +0300
Re: Common name for a "Task Loop" Wouter van Ooijen <wouter@voti.nl> - 2016-07-02 14:50 +0200
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-02 20:18 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-02 07:36 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-02 21:44 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-02 14:36 -0700
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-03 06:23 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-03 00:43 -0700
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-29 11:36 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-29 09:55 -0700
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-29 12:53 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-29 11:29 -0700
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-29 13:41 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-29 11:49 -0700
Re: Common name for a "Task Loop" Richard Damon <Richard@Damon-Family.org> - 2016-07-02 20:48 -0700
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-03 03:07 -0500
Re: Common name for a "Task Loop" Richard Damon <Richard@Damon-Family.org> - 2016-07-03 08:06 -0700
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-03 12:39 -0500
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-03 21:44 +0300
Re: Common name for a "Task Loop" Richard Damon <Richard@Damon-Family.org> - 2016-07-03 16:39 -0700
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-03 23:57 -0500
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-04 14:39 -0500
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-05 06:04 +0300
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-07-05 11:58 -0500
Re: Common name for a "Task Loop" Reinhardt Behm <rbehm@hushmail.com> - 2016-07-06 10:39 +0800
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-07-06 10:11 -0500
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-05 21:57 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-05 12:20 -0700
Re: Common name for a "Task Loop" Richard Damon <Richard@Damon-Family.org> - 2016-07-04 10:08 -0700
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-05 11:59 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-05 22:51 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-05 13:16 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-06 11:31 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-06 03:06 -0700
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-06 21:37 +0300
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-07 00:50 -0400
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-06 23:16 -0700
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-07 21:36 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-07 12:06 -0700
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-07 23:09 +0300
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-07-08 11:06 -0500
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-08 12:50 -0500
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-08 23:33 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-08 16:40 -0500
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-08 23:47 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-08 16:48 -0500
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-09 21:37 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-09 14:26 -0500
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-10 00:48 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-10 03:29 -0500
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-11 06:51 +0300
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-11 16:11 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-11 12:04 -0500
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-12 11:31 +0300
Re: Common name for a "Task Loop" mac <acolvin@efunct.com> - 2016-07-12 15:08 +0000
Re: Common name for a "Task Loop" Robert Wessel <robertwessel2@yahoo.com> - 2016-07-12 21:24 -0500
Memory scrubbing [Was Re: Common name for a "Task Loop"] Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-12 21:11 +0300
Re: Common name for a "Task Loop" Robert Wessel <robertwessel2@yahoo.com> - 2016-07-12 21:11 -0500
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-08 23:35 +0300
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-08 23:54 +0300
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-09 09:34 +0300
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-09 10:28 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-09 14:39 -0500
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-07-08 16:56 -0500
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-09 15:46 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-10 02:41 -0700
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-10 17:55 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-16 16:34 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-17 09:56 +0300
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-18 00:08 -0400
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-18 21:16 +0300
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-18 23:54 -0400
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-19 10:02 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-25 02:56 -0700
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-25 02:40 -0700
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-25 17:32 -0400
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-25 16:56 -0700
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-26 06:27 -0400
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-26 15:59 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-26 06:55 -0700
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-26 17:14 +0300
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-26 12:50 -0400
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-26 22:07 -0700
Re: Common name for a "Task Loop" George Neuner <gneuner2@comcast.net> - 2016-07-27 14:22 -0400
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-08-03 04:58 -0700
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-26 06:38 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-07-09 01:28 +0300
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-09 09:25 +0300
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-09 21:47 +0300
Re: Common name for a "Task Loop" Mike Perkins <spam@spam.com> - 2016-07-09 11:18 +0100
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-09 21:41 +0300
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-07-09 20:52 -0500
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-07-10 02:01 -0700
Re: Common name for a "Task Loop" Niklas Holsti <niklas.holsti@tidorum.invalid> - 2016-07-10 17:34 +0300
Re: Common name for a "Task Loop" [long] Don Y <blockedofcourse@foo.invalid> - 2016-07-17 01:17 -0700
Re: Common name for a "Task Loop" Tim Wescott <seemywebsite@myfooter.really> - 2016-07-07 16:02 -0500
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-30 04:14 +0300
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-30 17:07 -0500
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-07-01 02:28 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 12:02 -0700
Re: Common name for a "Task Loop" Hans-Bernhard Bröker <HBBroeker@t-online.de> - 2016-06-28 23:19 +0200
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-28 11:51 -0700
Re: Common name for a "Task Loop" Simon Clubley <clubley@remove_me.eisner.decus.org-Earth.UFP> - 2016-07-01 06:54 +0000
Re: Common name for a "Task Loop" Dimiter_Popoff <dp@tgi-sci.com> - 2016-06-25 21:08 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-25 15:24 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-25 21:52 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 01:04 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-26 13:46 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 05:11 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-26 15:35 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 06:57 -0700
Re: Common name for a "Task Loop" Reinhardt Behm <rbehm@hushmail.com> - 2016-06-26 21:18 +0800
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 07:07 -0700
Re: Common name for a "Task Loop" upsidedown@downunder.com - 2016-06-26 17:35 +0300
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 07:50 -0700
Re: Common name for a "Task Loop" Reinhardt Behm <rbehm@hushmail.com> - 2016-06-26 22:37 +0800
Re: Common name for a "Task Loop" Don Y <blockedofcourse@foo.invalid> - 2016-06-26 08:18 -0700
Re: Common name for a "Task Loop" Dave Nadler <drn@nadler.com> - 2016-06-25 22:00 -0700
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-26 11:01 -0500
Re: Common name for a "Task Loop" Les Cargill <lcargill99@comcast.com> - 2016-06-26 19:28 -0500
Re: Common name for a "Task Loop" FreeRTOS info <noemail@given.com> - 2016-06-27 08:33 +0100
Re: Common name for a "Task Loop" Tim Wescott <tim@seemywebsite.com> - 2016-06-28 09:48 -0500
Re: Common name for a "Task Loop" raimond.dragomir@gmail.com - 2016-06-28 08:25 -0700
Re: Common name for a "Task Loop" Chris <xxx.syseng.yyy@gfsys.co.uk> - 2016-07-03 17:39 +0000
Re: Common name for a "Task Loop" WangoTango <Asgard24@mindspring.com> - 2016-07-14 16:27 -0400
Re: Common name for a "Task Loop" Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2016-07-14 20:44 +0000
Page 4 of 10 — ← Prev page 1 2 3 [4] 5 6 … 10 Next page →
| From | Tim Wescott <seemywebsite@myfooter.really> |
|---|---|
| Date | 2016-06-28 17:39 -0500 |
| Message-ID | <WKqdnRfbXJY_Ye_KnZ2dnUU7-L-dnZ2d@giganews.com> |
| In reply to | #24421 |
On Wed, 29 Jun 2016 01:00:02 +0300, Dimiter_Popoff wrote: > On 28.6.2016 г. 17:40, Tim Wescott wrote: >> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote: >> >>> On 28.6.2016 г. 05:54, Simon Clubley wrote: >>>> >>> > ..... >>>> I still think that's a polling loop because you are reaching out to >>>> the sensor and asking it for it's current value. >>> >>> "Polling" in programming means "as opposed to interrupt handling". >>> How is this opposed to "interrupt handling". >>> >>> What you suggest to be polling is simply a loop of calls to >>> subroutines. >>> A "call loop" is what describes it - although it does not matter a lot >>> what word is used as long as it is not an already widely accepted one >>> like "polling" which you want to redefine. Nothing wrong with that of >>> course - as long as you don't have to communicate with other people >>> using your redefined term. >>> >>> So much talk about so little :-). Although Tim's topic idea worked, >>> produced quite a discussion. >> >> Well, I was hoping for a name of a design pattern, and I'm still not >> happy about my choices. So from that perspective it's a wash. >> >> "Super loop" seems closest, but it seems to more capture the notion of >> _always_ executing A, B, C, rather than executing only those bits that >> are ready. >> >> > I encounter the "super loop" term for the first time here, but why not. > Although I see nothing "super" about it, to me this is still an endless > loop of calls to subroutines either of which may opt to do something or > to just return if it has nothing to do. > But like I said earlier I have almost never used this approach, it > smells of oversimplifying - thus costing more than a decent scheduler > does. Implement loops, state machines etc. as you like within tasks but > having a true - preemptive allowing cooperative operation- scheduler > costs very little in both machine resources and effort to put together > so I see no point in trying to avoid it. The "scheduler" overhead is about 10x lower with this style of switching. If you've got a bunch of similar-run-length tasks this method works dandy. Of course, if you've got a bunch of fast tasks and even one slow one (reciting the Gettysburg address to a human, for instance) then a preemptive scheduler gets very attractive. -- Tim Wescott Wescott Design Services http://www.wescottdesign.com I'm looking for work -- see my website!
[toc] | [prev] | [next] | [standalone]
| From | Dimiter_Popoff <dp@tgi-sci.com> |
|---|---|
| Date | 2016-06-29 02:29 +0300 |
| Message-ID | <nkv19h$jjq$1@dont-email.me> |
| In reply to | #24426 |
On 29.6.2016 г. 01:39, Tim Wescott wrote: > On Wed, 29 Jun 2016 01:00:02 +0300, Dimiter_Popoff wrote: > >> On 28.6.2016 г. 17:40, Tim Wescott wrote: >>> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote: >>> >>>> On 28.6.2016 г. 05:54, Simon Clubley wrote: >>>>> >>>> > ..... >>>>> I still think that's a polling loop because you are reaching out to >>>>> the sensor and asking it for it's current value. >>>> >>>> "Polling" in programming means "as opposed to interrupt handling". >>>> How is this opposed to "interrupt handling". >>>> >>>> What you suggest to be polling is simply a loop of calls to >>>> subroutines. >>>> A "call loop" is what describes it - although it does not matter a lot >>>> what word is used as long as it is not an already widely accepted one >>>> like "polling" which you want to redefine. Nothing wrong with that of >>>> course - as long as you don't have to communicate with other people >>>> using your redefined term. >>>> >>>> So much talk about so little :-). Although Tim's topic idea worked, >>>> produced quite a discussion. >>> >>> Well, I was hoping for a name of a design pattern, and I'm still not >>> happy about my choices. So from that perspective it's a wash. >>> >>> "Super loop" seems closest, but it seems to more capture the notion of >>> _always_ executing A, B, C, rather than executing only those bits that >>> are ready. >>> >>> >> I encounter the "super loop" term for the first time here, but why not. >> Although I see nothing "super" about it, to me this is still an endless >> loop of calls to subroutines either of which may opt to do something or >> to just return if it has nothing to do. >> But like I said earlier I have almost never used this approach, it >> smells of oversimplifying - thus costing more than a decent scheduler >> does. Implement loops, state machines etc. as you like within tasks but >> having a true - preemptive allowing cooperative operation- scheduler >> costs very little in both machine resources and effort to put together >> so I see no point in trying to avoid it. > > The "scheduler" overhead is about 10x lower with this style of > switching. If you've got a bunch of similar-run-length tasks this method > works dandy. Well it is perhaps 10x in terms of processing time but that makes it within 1% of the time instead of within 0.1%. I mentioned earlier I once (some 10years ago) I did a thing using the "loop" approach and in hindsight I can say it cost me more time (I had plenty of CPU resources to spare so other considerations just do not apply). > > Of course, if you've got a bunch of fast tasks and even one slow one > (reciting the Gettysburg address to a human, for instance) then a > preemptive scheduler gets very attractive. > I see the preemptive feature mostly as a backup plan, basically if the reciter is say reciting through an UART at 9600 bps the output driver would be exiting the task cooperatively long before being preempted (say after filling an output FIFO of some 256 bytes or something). But if the system is dynamic - e.g. a fullblown OS with a user in front of it doing this and that - then preemption may well have to kick in. Dimiter ------------------------------------------------------ Dimiter Popoff, TGI http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/
[toc] | [prev] | [next] | [standalone]
| From | Tim Wescott <tim@seemywebsite.com> |
|---|---|
| Date | 2016-06-29 09:50 -0500 |
| Message-ID | <TIWdnUZZHPmxfe7KnZ2dnUU7-RGdnZ2d@giganews.com> |
| In reply to | #24433 |
On Wed, 29 Jun 2016 02:29:54 +0300, Dimiter_Popoff wrote: > On 29.6.2016 г. 01:39, Tim Wescott wrote: >> On Wed, 29 Jun 2016 01:00:02 +0300, Dimiter_Popoff wrote: >> >>> On 28.6.2016 г. 17:40, Tim Wescott wrote: >>>> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote: >>>> >>>>> On 28.6.2016 г. 05:54, Simon Clubley wrote: >>>>>> >>>>> > ..... >>>>>> I still think that's a polling loop because you are reaching out to >>>>>> the sensor and asking it for it's current value. >>>>> >>>>> "Polling" in programming means "as opposed to interrupt handling". >>>>> How is this opposed to "interrupt handling". >>>>> >>>>> What you suggest to be polling is simply a loop of calls to >>>>> subroutines. >>>>> A "call loop" is what describes it - although it does not matter a >>>>> lot what word is used as long as it is not an already widely >>>>> accepted one like "polling" which you want to redefine. Nothing >>>>> wrong with that of course - as long as you don't have to communicate >>>>> with other people using your redefined term. >>>>> >>>>> So much talk about so little :-). Although Tim's topic idea worked, >>>>> produced quite a discussion. >>>> >>>> Well, I was hoping for a name of a design pattern, and I'm still not >>>> happy about my choices. So from that perspective it's a wash. >>>> >>>> "Super loop" seems closest, but it seems to more capture the notion >>>> of _always_ executing A, B, C, rather than executing only those bits >>>> that are ready. >>>> >>>> >>> I encounter the "super loop" term for the first time here, but why >>> not. >>> Although I see nothing "super" about it, to me this is still an >>> endless loop of calls to subroutines either of which may opt to do >>> something or to just return if it has nothing to do. >>> But like I said earlier I have almost never used this approach, it >>> smells of oversimplifying - thus costing more than a decent scheduler >>> does. Implement loops, state machines etc. as you like within tasks >>> but having a true - preemptive allowing cooperative operation- >>> scheduler costs very little in both machine resources and effort to >>> put together so I see no point in trying to avoid it. >> >> The "scheduler" overhead is about 10x lower with this style of >> switching. If you've got a bunch of similar-run-length tasks this >> method works dandy. > > Well it is perhaps 10x in terms of processing time but that makes it > within 1% of the time instead of within 0.1%. I mentioned earlier I once > (some 10years ago) I did a thing using the "loop" approach and in > hindsight I can say it cost me more time (I had plenty of CPU resources > to spare so other considerations just do not apply). The only times when the "super loop" architecture that I showed is really appropriate is when the problem is small or when the processor is being pushed too hard. Otherwise -- yes, use an RTOS. -- Tim Wescott Control systems, embedded software and circuit design I'm looking for work! See my website if you're interested http://www.wescottdesign.com
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-06-28 15:43 -0700 |
| Message-ID | <nkuuhj$brp$1@dont-email.me> |
| In reply to | #24421 |
hi Dimiter, On 6/28/2016 3:00 PM, Dimiter_Popoff wrote: > I encounter the "super loop" term for the first time here, but why not. > Although I see nothing "super" about it, to me this is still an endless > loop of calls to subroutines either of which may opt to do something > or to just return if it has nothing to do. > But like I said earlier I have almost never used this approach, it > smells of oversimplifying - thus costing more than a decent scheduler > does. Implement loops, state machines etc. as you like within tasks > but having a true - preemptive allowing cooperative operation- scheduler > costs very little in both machine resources and effort to put together > so I see no point in trying to avoid it. I don't think you're understanding the value for "lean" approaches when you are operating in resource starved implementations. Imagine having a few HUNDRED bytes of RAM, *total* in your system. How much of this do you "divert" to implementing a formal scheduler? How much do you devote to preserving the state(s) of independant tasks? One of my earliest products was a LORAN-C position plotter. It received LORAN coordinates (time-difference pairs) from an external LORAN (radio) receiver. These are ~6 (decimal) digit values that represent the differences, in time, between radio waves being received from three geographically-fixed transmitters (a master and a pair of slaves; the slaves synchronized to the master) <https://en.wikipedia.org/wiki/LORAN#Operation> not a very good explanation -- but close enough. <https://en.wikipedia.org/wiki/Loran-C#Principle> As they are *differences*, they present a hyperbolic coordinate system (back to Conic Sections 101 :> ). Based on knowledge of where these transmitters are located on the globe (latitude and longitude!), you project the hyperbolic coordinate system onto the spherical coordinate system of lat-lon (as used in navigation). Then, correct for the fact that the Earth is an OBLATE sphere (not really *round*). Finally, map these onto a mercator map projection (the precisely scaled sheet of paper -- aka MAP -- in your plotter on which your pen will be drawing!) and drive the pen to the "current position" from its previous position. While the displays, keypad, stepping motor interfaces, etc. can all use nice little integers, all of this navigational math has to be done using floats. Each "coordinate" (whether in the hyperbolic, spherical/oblate, mercator coordinate system) is thus a PAIR of floats. With 256 bytes of RAM to play with (remember the pushdown stack and EVERY RAM consumer), you really don't have spare *bits*, let alone *bytes*, to devote to any sort of formal scheduling framework. E.g., the only time I bother with something as crude as (my version of) the "big loop" is when I am operating in these severely constrained environments. My implementation costs me EXACTLY *two* bytes per task. Yet, allows me to still write code AS IF I had the services and framework of a "real" scheduler. I.e., I don't force tasks to watch a hardware counter/timer to do their *own* timekeeping; I don't force a task to rely on exclusive access to a physical resource (e.g., N tasks can all "use the UART" instead of restricting access to just one set aside for that specific purpose); I don't prevent tasks from blocking WHEREVER IT IS CONVENIENT FOR THEM; etc. So, each task can truly focus on its own needs without having to address the concerns of other tasks (except for any data/events that it must "source" to those tasks). I think your current product offerings are REALLY "flush" with resources, by comparison. E.g., you (and I) wouldn't think twice about using an "int" (32b!) as a "bool". By contrast, the plotter mentioned above packed *8* bools into a byte -- and, at some times, might use that very same byte as a *counter*, etc. depending on what was happening in the product at that time!
[toc] | [prev] | [next] | [standalone]
| From | Dimiter_Popoff <dp@tgi-sci.com> |
|---|---|
| Date | 2016-06-29 02:40 +0300 |
| Message-ID | <nkv1to$l72$1@dont-email.me> |
| In reply to | #24427 |
On 29.6.2016 г. 01:43, Don Y wrote: > hi Dimiter, > > On 6/28/2016 3:00 PM, Dimiter_Popoff wrote: >> I encounter the "super loop" term for the first time here, but why not. >> Although I see nothing "super" about it, to me this is still an endless >> loop of calls to subroutines either of which may opt to do something >> or to just return if it has nothing to do. >> But like I said earlier I have almost never used this approach, it >> smells of oversimplifying - thus costing more than a decent scheduler >> does. Implement loops, state machines etc. as you like within tasks >> but having a true - preemptive allowing cooperative operation- scheduler >> costs very little in both machine resources and effort to put together >> so I see no point in trying to avoid it. > > I don't think you're understanding the value for "lean" approaches > when you are operating in resource starved implementations. > > Imagine having a few HUNDRED bytes of RAM, *total* in your system. > How much of this do you "divert" to implementing a formal scheduler? > How much do you devote to preserving the state(s) of independant tasks? Hi Don, I think I addressed this in my reply to Hans a short time ago. My estimate was that for 5-6 tasks at 512 bytes of RAM you'd spend about 20% of it on multitasking. If you opt for the superloop approach you will still need some stack etc., let us say 5%. Which means you will have spent about 80 bytes on having a good scheduler - which would likely be a good deal in most cases (and of course I can see there can be extreme cases where one just does not have the 80 bytes). > > One of my earliest products was a LORAN-C position plotter. It > received LORAN coordinates (time-difference pairs) from an external > LORAN (radio) receiver. These are ~6 (decimal) digit values that > represent the differences, in time, between radio waves being > received from three geographically-fixed transmitters (a master > and a pair of slaves; the slaves synchronized to the master) > > <https://en.wikipedia.org/wiki/LORAN#Operation> not a very > good explanation -- but close enough. > <https://en.wikipedia.org/wiki/Loran-C#Principle> > > As they are *differences*, they present a hyperbolic coordinate > system (back to Conic Sections 101 :> ). Based on knowledge > of where these transmitters are located on the globe (latitude > and longitude!), you project the hyperbolic coordinate system > onto the spherical coordinate system of lat-lon (as used in > navigation). Then, correct for the fact that the Earth is > an OBLATE sphere (not really *round*). Finally, map these > onto a mercator map projection (the precisely scaled sheet of > paper -- aka MAP -- in your plotter on which your pen will be > drawing!) and drive the pen to the "current position" from its > previous position. > > While the displays, keypad, stepping motor interfaces, etc. > can all use nice little integers, all of this navigational > math has to be done using floats. Each "coordinate" > (whether in the hyperbolic, spherical/oblate, mercator > coordinate system) is thus a PAIR of floats. > > With 256 bytes of RAM to play with (remember the pushdown stack > and EVERY RAM consumer), you really don't have spare *bits*, > let alone *bytes*, to devote to any sort of formal scheduling > framework. Well this is a good example of an extreme case where it is worth going to extra length to save each byte of RAM, of course. > .... > > I think your current product offerings are REALLY "flush" with > resources, by comparison. E.g., you (and I) wouldn't think twice > about using an "int" (32b!) as a "bool". By contrast, the plotter > mentioned above packed *8* bools into a byte -- and, at some > times, might use that very same byte as a *counter*, etc. depending > on what was happening in the product at that time! > We all have plenty of resources nowadays indeed, which is why I think a scheduler is the normal way to go. But I do not use a longword as "bool", almost never. Typically I call it "flag" and define bits into it... then often I (have to) use atomic accesses to it etc. :-). Dimiter ------------------------------------------------------ Dimiter Popoff, TGI http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-06-28 16:56 -0700 |
| Message-ID | <nkv2rb$nnm$1@dont-email.me> |
| In reply to | #24435 |
On 6/28/2016 4:40 PM, Dimiter_Popoff wrote: > We all have plenty of resources nowadays indeed, which is why > I think a scheduler is the normal way to go. But I do not use a longword I don't think that is universally the case. I think there still exist "penny pinching" applications. OTOH, I think many of those could, for the same effective cost, move up to more featureful implementations if not for "design inertia" I've played at the shallow end of the pool for a long time. Now I'm enjoying "the deep end" -- and the VERY deep end! There are entirely different issues present that you'd never get exposed to if you kept playing in the "wading pool" :-/ > as "bool", almost never. Typically I call it "flag" and define > bits into it... then often I (have to) use atomic accesses to it > etc. :-).
[toc] | [prev] | [next] | [standalone]
| From | upsidedown@downunder.com |
|---|---|
| Date | 2016-06-29 08:04 +0300 |
| Message-ID | <6cl6nb99aa54apfq3b179m7uoeir9dc3jj@4ax.com> |
| In reply to | #24427 |
On Tue, 28 Jun 2016 15:43:03 -0700, Don Y <blockedofcourse@foo.invalid> wrote: >Imagine having a few HUNDRED bytes of RAM, *total* in your system. >How much of this do you "divert" to implementing a formal scheduler? >How much do you devote to preserving the state(s) of independant tasks? With a stack oriented HLL like Pascal r C, the variables are already in the (private) stacks, only the CPU registers needs to be saved, thus only a few extra bytes needs to be allocated in each local stack in addition to the application variables.
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-06-28 23:22 -0700 |
| Message-ID | <nkvpfn$civ$1@dont-email.me> |
| In reply to | #24437 |
On 6/28/2016 10:04 PM, upsidedown@downunder.com wrote: > On Tue, 28 Jun 2016 15:43:03 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >> Imagine having a few HUNDRED bytes of RAM, *total* in your system. >> How much of this do you "divert" to implementing a formal scheduler? >> How much do you devote to preserving the state(s) of independant tasks? > > With a stack oriented HLL like Pascal r C, the variables are already > in the (private) stacks, only the CPU registers needs to be saved, > thus only a few extra bytes needs to be allocated in each local stack > in addition to the application variables. Ah, but that's the problem! You now need stacks for each task (each large enough to satisfy the task's worst case stack penetration *plus* any stack required by ISRs -- as they can occur during any task's "time slot"). You can save JUST the SP for each task and use that to "recover" the stack and CPU registers (saved on the stack during the context switch). But, you will alwyas be tempted to yield() (or equivalent) at some arbitrary depth on the stack. I.e., you can have a dozen stack frames nested FOR THIS TASK and decide to yield() -- now, all of those stack frames must be preserved as part of the task's state (because you picked a "less than ideal place" to yield the processor to the "next" task) If, instead, you impose a discipline on when you can yield, then you can eliminate the need to preserve any of this "stacked state". E.g., only "yield" when the SP is at the level it is at between calls out from the big loop. Then, all you need to do is save the processor state (registers plus PC; the SP will be *known* to be "fixed" in all such invocations with NOTHING on the stack!) If you take a step further and allow yield() to be invoked ANY TIME YOU CARE NOTHING ABOUT THE REGISTER CONTENTS, then you don't even have to save those! That's the premise of the MTX I described in my other posts (and the reason it can function with just 2 bytes per task -- the PC). If you're working in tiny environments, you probably are willing -- even EAGER -- to shed the sorts of overhead that you typically draw into the mix with HLL's; yet, you sacrifice relatively little in terms of capability (cuz you're not building giant applications with negligible resources!)
[toc] | [prev] | [next] | [standalone]
| From | upsidedown@downunder.com |
|---|---|
| Date | 2016-06-30 09:02 +0300 |
| Message-ID | <smb9nb1rmauevd5murpt9b6vjpjek8e23s@4ax.com> |
| In reply to | #24438 |
On Tue, 28 Jun 2016 23:22:51 -0700, Don Y <blockedofcourse@foo.invalid> wrote: >On 6/28/2016 10:04 PM, upsidedown@downunder.com wrote: >> On Tue, 28 Jun 2016 15:43:03 -0700, Don Y >> <blockedofcourse@foo.invalid> wrote: >> >>> Imagine having a few HUNDRED bytes of RAM, *total* in your system. >>> How much of this do you "divert" to implementing a formal scheduler? >>> How much do you devote to preserving the state(s) of independant tasks? >> >> With a stack oriented HLL like Pascal r C, the variables are already >> in the (private) stacks, only the CPU registers needs to be saved, >> thus only a few extra bytes needs to be allocated in each local stack >> in addition to the application variables. > >Ah, but that's the problem! You now need stacks for each task >(each large enough to satisfy the task's worst case stack penetration >*plus* any stack required by ISRs -- as they can occur during any >task's "time slot"). > >You can save JUST the SP for each task and use that to "recover" >the stack and CPU registers (saved on the stack during the context >switch). > >But, you will alwyas be tempted to yield() (or equivalent) at some >arbitrary depth on the stack. I.e., you can have a dozen stack >frames nested FOR THIS TASK and decide to yield() -- now, all of those >stack frames must be preserved as part of the task's state (because >you picked a "less than ideal place" to yield the processor to the >"next" task) In preemptive systems you usually talk about a task becoming not ready e.g. waiting for some event. Some systems execute a Software Interrupt type instruction stacking the registers as a real interrupt would do. The stack pointer is saved into the kernel data structure. There are no nested saved register sets, there is just _one_ saved register set at the top of the stack. When the task finally becomes ready to run, the scheduler reloads the task stack pointer and then performs a Return From Interrupt, which pops the registers and continues with the instruction following the Software Interrupt instruction. So there are at most one saved register set in the task specific stack and it is located at the top of the stack.
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-06-30 02:33 -0700 |
| Message-ID | <nl2p13$oqb$1@dont-email.me> |
| In reply to | #24477 |
On 6/29/2016 11:02 PM, upsidedown@downunder.com wrote: >> Ah, but that's the problem! You now need stacks for each task >> (each large enough to satisfy the task's worst case stack penetration >> *plus* any stack required by ISRs -- as they can occur during any >> task's "time slot"). >> >> You can save JUST the SP for each task and use that to "recover" >> the stack and CPU registers (saved on the stack during the context >> switch). >> >> But, you will alwyas be tempted to yield() (or equivalent) at some >> arbitrary depth on the stack. I.e., you can have a dozen stack >> frames nested FOR THIS TASK and decide to yield() -- now, all of those >> stack frames must be preserved as part of the task's state (because >> you picked a "less than ideal place" to yield the processor to the >> "next" task) > > In preemptive systems you usually talk about a task becoming not ready > e.g. waiting for some event. Some systems execute a Software Interrupt > type instruction stacking the registers as a real interrupt would do. > The stack pointer is saved into the kernel data structure. > > There are no nested saved register sets, there is just _one_ saved > register set at the top of the stack. > > When the task finally becomes ready to run, the scheduler reloads the > task stack pointer and then performs a Return From Interrupt, which > pops the registers and continues with the instruction following the > Software Interrupt instruction. > > So there are at most one saved register set in the task specific stack > and it is located at the top of the stack. And the other tasks have NO stacks? And no "processor state" stored? Note the "stack frames" that I mentioned, above, refer to the nesting of *function calls* (or subroutine invocations) within each specific task. I.e., you have no way of knowing how "deep" each task's stack happens to be when the task is preempted or voluntarily yields control of the processor. At that point, ALL of the task's state must be preserved: its CPU registers and its "live" stack. Repeat for all tasks in the system. If, instead, you ensure all context switches occur when there is NOTHING on the "task-specific stack", then all tasks can SHARE a stack (because you've ensured that the stack will be empty BEFORE you allow a reschedule() event). As such, the memory required for the stack is the maximum stack penetration of ANY task -- plus the maximum usage for the foreground (ISR) system. Contrast this with the maximum stack penetration for *each* task, plus the maximum ISR penetration SUMMED for all tasks in the system. (Some processors let you specify a separate stack for ISR's. In which case, you can eliminate the cost of the ISR stack PER TASK)
[toc] | [prev] | [next] | [standalone]
| From | upsidedown@downunder.com |
|---|---|
| Date | 2016-07-02 14:27 +0300 |
| Message-ID | <j58fnbl2giluke621jdgjfsahnak14jcfm@4ax.com> |
| In reply to | #24480 |
On Thu, 30 Jun 2016 02:33:24 -0700, Don Y <blockedofcourse@foo.invalid> wrote: >On 6/29/2016 11:02 PM, upsidedown@downunder.com wrote: > >>> Ah, but that's the problem! You now need stacks for each task >>> (each large enough to satisfy the task's worst case stack penetration >>> *plus* any stack required by ISRs -- as they can occur during any >>> task's "time slot"). >>> >>> You can save JUST the SP for each task and use that to "recover" >>> the stack and CPU registers (saved on the stack during the context >>> switch). >>> >>> But, you will alwyas be tempted to yield() (or equivalent) at some >>> arbitrary depth on the stack. I.e., you can have a dozen stack >>> frames nested FOR THIS TASK and decide to yield() -- now, all of those >>> stack frames must be preserved as part of the task's state (because >>> you picked a "less than ideal place" to yield the processor to the >>> "next" task) >> >> In preemptive systems you usually talk about a task becoming not ready >> e.g. waiting for some event. Some systems execute a Software Interrupt >> type instruction stacking the registers as a real interrupt would do. >> The stack pointer is saved into the kernel data structure. >> >> There are no nested saved register sets, there is just _one_ saved >> register set at the top of the stack. >> >> When the task finally becomes ready to run, the scheduler reloads the >> task stack pointer and then performs a Return From Interrupt, which >> pops the registers and continues with the instruction following the >> Software Interrupt instruction. >> >> So there are at most one saved register set in the task specific stack >> and it is located at the top of the stack. > >And the other tasks have NO stacks? And no "processor state" stored? After working for several decades with preemptive kernels, I thought it is self-evident that a preemptive system requires task specific stacks !! > >Note the "stack frames" that I mentioned, above, refer to the nesting of >*function calls* (or subroutine invocations) within each specific task. >I.e., you have no way of knowing how "deep" each task's stack happens to >be when the task is preempted or voluntarily yields control of the >processor. This is not relevant to the context saving discussion. You can do a quite good static stack usage analysis based on static code analysis. In many systems recursive calls are forbidden exactly for that reason. >At that point, ALL of the task's state must be preserved: its CPU registers >and its "live" stack. Self-evident.
[toc] | [prev] | [next] | [standalone]
| From | Wouter van Ooijen <wouter@voti.nl> |
|---|---|
| Date | 2016-07-02 14:50 +0200 |
| Message-ID | <5777b8a0$0$22216$e4fe514c@newszilla.xs4all.nl> |
| In reply to | #24511 |
Op 02-Jul-16 om 1:27 PM schreef upsidedown@downunder.com: > On Thu, 30 Jun 2016 02:33:24 -0700, Don Y > <blockedofcourse@foo.invalid> wrote: > >> On 6/29/2016 11:02 PM, upsidedown@downunder.com wrote: >> >>>> Ah, but that's the problem! You now need stacks for each task >>>> (each large enough to satisfy the task's worst case stack penetration >>>> *plus* any stack required by ISRs -- as they can occur during any >>>> task's "time slot"). >>>> >>>> You can save JUST the SP for each task and use that to "recover" >>>> the stack and CPU registers (saved on the stack during the context >>>> switch). >>>> >>>> But, you will alwyas be tempted to yield() (or equivalent) at some >>>> arbitrary depth on the stack. I.e., you can have a dozen stack >>>> frames nested FOR THIS TASK and decide to yield() -- now, all of those >>>> stack frames must be preserved as part of the task's state (because >>>> you picked a "less than ideal place" to yield the processor to the >>>> "next" task) >>> >>> In preemptive systems you usually talk about a task becoming not ready >>> e.g. waiting for some event. Some systems execute a Software Interrupt >>> type instruction stacking the registers as a real interrupt would do. >>> The stack pointer is saved into the kernel data structure. >>> >>> There are no nested saved register sets, there is just _one_ saved >>> register set at the top of the stack. >>> >>> When the task finally becomes ready to run, the scheduler reloads the >>> task stack pointer and then performs a Return From Interrupt, which >>> pops the registers and continues with the instruction following the >>> Software Interrupt instruction. >>> >>> So there are at most one saved register set in the task specific stack >>> and it is located at the top of the stack. >> >> And the other tasks have NO stacks? And no "processor state" stored? > > After working for several decades with preemptive kernels, I thought > it is self-evident that a preemptive system requires task specific > stacks !! > >> >> Note the "stack frames" that I mentioned, above, refer to the nesting of >> *function calls* (or subroutine invocations) within each specific task. >> I.e., you have no way of knowing how "deep" each task's stack happens to >> be when the task is preempted or voluntarily yields control of the >> processor. > > This is not relevant to the context saving discussion. > > You can do a quite good static stack usage analysis based on static > code analysis. In many systems recursive calls are forbidden exactly > for that reason. Do you have experience (or know) any tools that do this? Wouter "Objects? No Thanks!" van Ooijen
[toc] | [prev] | [next] | [standalone]
| From | Niklas Holsti <niklas.holsti@tidorum.invalid> |
|---|---|
| Date | 2016-07-02 20:18 +0300 |
| Message-ID | <dtqbbbF846cU1@mid.individual.net> |
| In reply to | #24512 |
On 16-07-02 15:50 , Wouter van Ooijen wrote:
> Op 02-Jul-16 om 1:27 PM schreef upsidedown@downunder.com:
>> On Thu, 30 Jun 2016 02:33:24 -0700, Don Y
>> <blockedofcourse@foo.invalid> wrote:
>>
>>> On 6/29/2016 11:02 PM, upsidedown@downunder.com wrote:
>>>
>>>>> Ah, but that's the problem! You now need stacks for each task
>>>>> (each large enough to satisfy the task's worst case stack penetration
>>>>> *plus* any stack required by ISRs -- as they can occur during any
>>>>> task's "time slot").
>>>>>
>>>>> You can save JUST the SP for each task and use that to "recover"
>>>>> the stack and CPU registers (saved on the stack during the context
>>>>> switch).
>>>>>
>>>>> But, you will alwyas be tempted to yield() (or equivalent) at some
>>>>> arbitrary depth on the stack. I.e., you can have a dozen stack
>>>>> frames nested FOR THIS TASK and decide to yield() -- now, all of those
>>>>> stack frames must be preserved as part of the task's state (because
>>>>> you picked a "less than ideal place" to yield the processor to the
>>>>> "next" task)
>>>>
>>>> In preemptive systems you usually talk about a task becoming not ready
>>>> e.g. waiting for some event. Some systems execute a Software Interrupt
>>>> type instruction stacking the registers as a real interrupt would do.
>>>> The stack pointer is saved into the kernel data structure.
>>>>
>>>> There are no nested saved register sets, there is just _one_ saved
>>>> register set at the top of the stack.
>>>>
>>>> When the task finally becomes ready to run, the scheduler reloads the
>>>> task stack pointer and then performs a Return From Interrupt, which
>>>> pops the registers and continues with the instruction following the
>>>> Software Interrupt instruction.
>>>>
>>>> So there are at most one saved register set in the task specific stack
>>>> and it is located at the top of the stack.
>>>
>>> And the other tasks have NO stacks? And no "processor state" stored?
>>
>> After working for several decades with preemptive kernels, I thought
>> it is self-evident that a preemptive system requires task specific
>> stacks !!
>>
>>>
>>> Note the "stack frames" that I mentioned, above, refer to the nesting of
>>> *function calls* (or subroutine invocations) within each specific task.
>>> I.e., you have no way of knowing how "deep" each task's stack happens to
>>> be when the task is preempted or voluntarily yields control of the
>>> processor.
>>
>> This is not relevant to the context saving discussion.
>>
>> You can do a quite good static stack usage analysis based on static
>> code analysis. In many systems recursive calls are forbidden exactly
>> for that reason.
>
> Do you have experience (or know) any tools that do this?
Google "static stack usage analysis" for links.
Compilers from IAR Systems can do it, at least for some targets.
AdaCore provide the "gnatstack" tool which can also do it, in
conjunction with AdaCore's compilers.
StackAnalyzer (www.absint.com) and Bound-T (www.bound-t.com) can do it.
GCC option "-fstack-usage" gives per-function stack usage. For the AVR
target, a Perl script can be used to add those up along call-paths to
get per-thread stack usage (http://dlbeer.co.nz/oss/avstack.html).
I have experience with Bound-T (well, I'm the developer) and some with
IAR compilers. As long as all calls and stack-space allocations are
static the tools work well; when either calls or stack allocations
become dynamic (e.g. virtual function calls) you run into problems, but
at least the commercial tools have means to work around those problems.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-07-02 07:36 -0700 |
| Message-ID | <nl8jh6$acj$1@dont-email.me> |
| In reply to | #24511 |
On 7/2/2016 4:27 AM, upsidedown@downunder.com wrote:
> On Thu, 30 Jun 2016 02:33:24 -0700, Don Y
>>>> But, you will alwyas be tempted to yield() (or equivalent) at some
>>>> arbitrary depth on the stack. I.e., you can have a dozen stack
>>>> frames nested FOR THIS TASK and decide to yield() -- now, all of those
>>>> stack frames must be preserved as part of the task's state (because
>>>> you picked a "less than ideal place" to yield the processor to the
>>>> "next" task)
>>>
>>> In preemptive systems you usually talk about a task becoming not ready
>>> e.g. waiting for some event. Some systems execute a Software Interrupt
>>> type instruction stacking the registers as a real interrupt would do.
>>> The stack pointer is saved into the kernel data structure.
>>>
>>> There are no nested saved register sets, there is just _one_ saved
>>> register set at the top of the stack.
>>>
>>> When the task finally becomes ready to run, the scheduler reloads the
>>> task stack pointer and then performs a Return From Interrupt, which
>>> pops the registers and continues with the instruction following the
>>> Software Interrupt instruction.
>>>
>>> So there are at most one saved register set in the task specific stack
>>> and it is located at the top of the stack.
>>
>> And the other tasks have NO stacks? And no "processor state" stored?
>
> After working for several decades with preemptive kernels, I thought
> it is self-evident that a preemptive system requires task specific
> stacks !!
Now, walk back up-thread to my comment to Dimiter:
Imagine having a few HUNDRED bytes of RAM, *total* in your system.
How much of this do you "divert" to implementing a formal scheduler?
How much do you devote to preserving the state(s) of independant tasks?
>> Note the "stack frames" that I mentioned, above, refer to the nesting of
>> *function calls* (or subroutine invocations) within each specific task.
>> I.e., you have no way of knowing how "deep" each task's stack happens to
>> be when the task is preempted or voluntarily yields control of the
>> processor.
>
> This is not relevant to the context saving discussion.
Again, walk back up-thread and please find try to see *if* I claimed it to
be part of the context switch.
You're missing the appeal of NOT including any "stacked task state" in
the PRESERVED TASK STATE; namely, that the amount of RAM that you dedicate
to stack usage -- ALL stacks -- in the design is the maximum of all
tasks' stack penetration plus the ISR penetration. You never have more
than one stack "live" in the system!
"If, instead, you ensure all context switches occur when there is NOTHING on
the 'task-specific stack', then all tasks can SHARE a stack (because you've
ensured that the stack will be empty BEFORE you allow a reschedule() event).
> You can do a quite good static stack usage analysis based on static
> code analysis. In many systems recursive calls are forbidden exactly
> for that reason.
>
>> At that point, ALL of the task's state must be preserved: its CPU registers
>> and its "live" stack.
>
> Self-evident.
But not necessary to work in a multitasking environment! Even with a HLL
(though operating with NOTHING preserved on the stack in a HLL environment
imposes lots of constraints -- with which the compiler WON'T help!):
task() {
some_variable_declarations; <---- disallowed
...
some_function();
...
taskX(); <---- disallowed
...
yield(); <---- allowed
...
}
some_function() {
...
yield(); <------ disallowed
...
}
OTOH, there's nothing wrong with:
task() {
...
global = value; <---- allowed
...
another_function(); <---- allowed
...
yield(); <---- allowed
...
}
another_function() {
some_variable_declarations;
...
some_other_function();
...
another_function(); // recursive
...
}
This latter form is quite "comfortable", after some experience.
(Replace C with your language of choice)
[toc] | [prev] | [next] | [standalone]
| From | upsidedown@downunder.com |
|---|---|
| Date | 2016-07-02 21:44 +0300 |
| Message-ID | <bt1gnbtdb83lcbavogvndi9s5ke5bqu9ad@4ax.com> |
| In reply to | #24513 |
On Sat, 02 Jul 2016 07:36:34 -0700, Don Y <blockedofcourse@foo.invalid> wrote: >On 7/2/2016 4:27 AM, upsidedown@downunder.com wrote: >> On Thu, 30 Jun 2016 02:33:24 -0700, Don Y > >>>>> But, you will alwyas be tempted to yield() (or equivalent) at some >>>>> arbitrary depth on the stack. I.e., you can have a dozen stack >>>>> frames nested FOR THIS TASK and decide to yield() -- now, all of those >>>>> stack frames must be preserved as part of the task's state (because >>>>> you picked a "less than ideal place" to yield the processor to the >>>>> "next" task) >>>> >>>> In preemptive systems you usually talk about a task becoming not ready >>>> e.g. waiting for some event. Some systems execute a Software Interrupt >>>> type instruction stacking the registers as a real interrupt would do. >>>> The stack pointer is saved into the kernel data structure. >>>> >>>> There are no nested saved register sets, there is just _one_ saved >>>> register set at the top of the stack. >>>> >>>> When the task finally becomes ready to run, the scheduler reloads the >>>> task stack pointer and then performs a Return From Interrupt, which >>>> pops the registers and continues with the instruction following the >>>> Software Interrupt instruction. >>>> >>>> So there are at most one saved register set in the task specific stack >>>> and it is located at the top of the stack. >>> >>> And the other tasks have NO stacks? And no "processor state" stored? >> >> After working for several decades with preemptive kernels, I thought >> it is self-evident that a preemptive system requires task specific >> stacks !! > >Now, walk back up-thread to my comment to Dimiter: > > Imagine having a few HUNDRED bytes of RAM, *total* in your system. > How much of this do you "divert" to implementing a formal scheduler? > How much do you devote to preserving the state(s) of independant tasks? On some small systems I have worked with, I have initially allocated 64 bytes stack space for each task or something more, if the manual static analysis would demand. Also filling each task with a known pattern and checking after a week how much has actually been used and reduced the stack allocation accordingly. In one case the kernel data structure was just 3 bytes for each task, two bytes to store the stack pointer for each task and one byte to contain the task state, such as not ready, ready and running.Slightly more RAM efficient would be to use 8 or 16 task states (runnable or not) into 1 or 2 bytes. With 64 bytes/task, you could fit 3 tasks into 200 bytes and six into 400 bytes of RAM.
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-07-02 14:36 -0700 |
| Message-ID | <nl9c3t$t0$1@dont-email.me> |
| In reply to | #24515 |
On 7/2/2016 11:44 AM, upsidedown@downunder.com wrote:
> With 64 bytes/task, you could fit 3 tasks into 200 bytes and six into
> 400 bytes of RAM.
With 3 tasks, you probably couldn't implement a municipal traffic light
controller! (don't forget the globals and ISR's)
(Yes, you could *do* it -- as one big spaghetti loop)
- Run the normal light cycle (go/caution/stop)
- Sense vehicles waiting in the turn lanes to conditionally qualify those
by injecting the "turn arrow" controls
- Sense traffic proceeding through the intersection and waiting at cross
streets (to adjust the timing of the cycles)
- Communicate with the other processes (so if oncoming is allowing left
turns, YOU should probably do so as well -- or not!)
- Sense a demand for a "walk" signal
- Control the walk/countdown/don't walk signals
- Monitor for on-coming emergency vehicles
- Indicate recognition of said vehicles and adjust traffic cycles accordingly.
- Communicate with municipal controlling algorithms/time-of-day scheduling.
- Allow on-site overrides.
- Support run-time diagnostics (fallback modes)
And, we're not even worrying about red-light cameras or general surveillance
cameras!
1980's era (arcade) video games would treat each object on the screen
as a task. So, 50 - 100 objects all acting independantly without
concern for their "neighbors" (unless their neighbor was something
that they could kill or be killed by).
I run 5 tasks to decode a barcode (without "consuming" it)
My "fallback" speech synthesizers each require more than a dozen tasks.
Etc.
I.e., I *like* decomposing projects into more manageable pieces -- get it
right the first time!
[toc] | [prev] | [next] | [standalone]
| From | Dimiter_Popoff <dp@tgi-sci.com> |
|---|---|
| Date | 2016-07-03 06:23 +0300 |
| Message-ID | <nla0fn$r3v$1@dont-email.me> |
| In reply to | #24516 |
On 03.7.2016 г. 00:36, Don Y wrote: > On 7/2/2016 11:44 AM, upsidedown@downunder.com wrote: >> With 64 bytes/task, you could fit 3 tasks into 200 bytes and six into >> 400 bytes of RAM. > > With 3 tasks, you probably couldn't implement a municipal traffic light > controller! (don't forget the globals and ISR's) Don, even splitting things in two tasks can be quite helpful. Say one handling the I/O and the other the rest. Having a multitask scheduler does not mean you don't use loops. You do of course - practically always. You just don't have to care about what the scheduler gives you in every subroutine you write - just call the "task exit for rescheduling" call when your code has to wait. If you don't have the scheduler you will have to care about this every step of the way, make sure you know where your current stack pointer is (subroutine calls; then a subroutine which exits cannot be just called from any nesting level etc. etc.). If we really have to count the bytes of RAM - let us say we turn the clock 25 years back - we can statically assign as much stack as needed to each task. We may find out that splitting in 3 tasks can at times _save_ memory above a certain complexity... I thought we'd be done with counting for days every byte by now, last "small" MCU I used was a coldfire in tqfp100 with 16k RAM and a sort of 68000 running at 80 MHz.... I just copied and slightly adapted the initial (68340 from 1994) DPS scheduler and trap handler, cost me virtually nothing. http://tgi-sci.com/dsv/swgboard.gif http://tgi-sci.com/dsv/swg800.gif http://tgi-sci.com/misc/PICT6999.avi http://tgi-sci.com/tgi/auxhv.htm No picture of the last, this MCU replaced a huge computer board in an 8 channel Ortec alpha counting system so they could use two netmca-s to simultaneously select any two vacuum chhambers to count, measure the vacuum and plenty of other internals, the analog part was intact). And such an MCU costs well below $10 at Mouser or the likes for a single piece.... Dimiter ------------------------------------------------------ Dimiter Popoff, TGI http://www.tgi-sci.com ------------------------------------------------------ http://www.flickr.com/photos/didi_tgi/
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-07-03 00:43 -0700 |
| Message-ID | <nlafmi$ukt$1@dont-email.me> |
| In reply to | #24518 |
Hi Dimiter,
On 7/2/2016 8:23 PM, Dimiter_Popoff wrote:
> On 03.7.2016 г. 00:36, Don Y wrote:
>> On 7/2/2016 11:44 AM, upsidedown@downunder.com wrote:
>>> With 64 bytes/task, you could fit 3 tasks into 200 bytes and six into
>>> 400 bytes of RAM.
>>
>> With 3 tasks, you probably couldn't implement a municipal traffic light
>> controller! (don't forget the globals and ISR's)
>
> Don, even splitting things in two tasks can be quite helpful. Say one
> handling the I/O and the other the rest.
Yes, but you ideally want to come up with a "natural decomposition";
how do things *want* to split themselves up instead of how *can* I
split them up.
I like doing lots of little things and getting them 100.0% correct
instead of trying to walk and chew gum -- and risking a latent bug.
E.g., the barcode decoder in the example I previously posted runs in 6 layers:
- an ISR grabs the contents of a freerunning two byte counter-timer using 3
byte-wide reads (H-L-H / L-H-L); it also reads another counter-timer (the
one that generated the IRQ from the rising/falling edge of the "video"
signal) to determine "how long ago" the actual edge occured (this allows
interrupt latency to be removed from the 3 byte read!); then, programs
the counter-timer to look for the "opposite" edge (black-to-white vs.
white-to-black)
- the first "background" task simply watches the FIFO maintained by the
ISR and extracts data as it becomes available; it notices special
encodings in the FIFO that indicate the ISR overran the FIFO (so,
data has been lost *at* that point -- but the data preceding it may
still represent a valid code); as it extracts each 4-byte entry, it
converts the 3-byte timer read into a 2-byte read (by noticing if the
low byte "wrapped" while the read was happening); then, uses the
"latency time" to adjust the 2-byte value to account for any delay
that might have been present when the IRQ was actually *serviced*;
it also passes flags that indicate if the 2-byte timer wrapped more
than once (cuz the ISR can be idle for long periods of time between
uses; 0x65535 and 0x0002 may have far more than 3 counts between them!).
So, this task's primary purpose is to keep the ISR FIFO empty cuz each
entry there consumes 4 bytes
- the second background task looks at these 2-byte counts (and any interspersed
flag encodings) and computes time *differences* between them. It knows
that the 2 byte counter might not be counting [0..65535] -- or even something
like [0..MAX_COUNT] -- rather, it can be counting ([0..MAX_LSB],[0..MAX_MSB])
so has to play games with modular arithmetic but can do the math /in situ/
without consuming any additional memory (recall the first background task
will be trying to fill *this* buffer as well!)
- the third grabs groups of 8 (?) "bars" (a "space" is essentially a bar)
and tries to see if the widths fit the ratios of the barcode that is
being decoded -- assuming the label has been scanned at a relatively
constant speed over the course of those bars/spaces; it reduces the
bars/spaces to a "character" in the format supported by the label.
If the widths defy the rules for the legal characters, it discards the
oldest bar/space and tries again
- the fourth looks at groups of characters to decide if they fit the
form of a label -- correct start character, number of characters,
check digit, stop character, etc. If not, then the oldest character
must be rejected (which means the oldest bar/space must be rejected
in the *third* task that feeds this. It also applies more "global"
tests in an attempt to discard dubious data (goal is to achieve a very
high "first pass read rate" but an even HIGHER *accuracy* level!). So,
it looks at things like how "fast" the label passed the point scanner
for each of the characters and argues as to whether it is possible
for that set of scanning speeds to be encountered "in such rapid
succession". E.g., if the first character appears to have been scanned
at a rate of 10 inches per second (based on the time-widths of the
bars and spaces that it is composed of) but the second character (one
tenth of an inch from the start of the first!) indicates a scanning speed
of 80 ips, we know something just isn't right and can discard the
oldest character, etc.
- Finally, the fifth level takes "whole labels" and tries to concatenate
them into "super labels" by recognizing certain start-stop character
combinations AND the time (physical distance between the end of one
and the start of the next) to see if they conform to a grammar that
allows them to be combined into a single, continuous label (with the
EMBEDDED start-stop characters elided)
On top of all this, you're also looking at the data in the context of it
being representative of a label scanned *backwards* -- so, the oldest
bar/space may, in fact, be the LAST one in the label, part of the LAST
character 9stop character), etc.
You can write this as one giant piece of spaghetti code. And, spend
a boatload of time trying to get it to work RELIABLY (note that you
have to allow a label to be scanned at ANY time, not just when the
user tells you "I'm going to scan a label, now!"). So, testing
is an abysmal way of assuring yourself that the code REALLY works!
Prove it on paper; verify it in the lab!
> Having a multitask scheduler does not mean you don't use loops. You do
> of course - practically always. You just don't have to care about what
> the scheduler gives you in every subroutine you write - just call the
> "task exit for rescheduling" call when your code has to wait. If you
> don't have the scheduler you will have to care about this every step of
> the way, make sure you know where your current stack pointer is
> (subroutine calls; then a subroutine which exits cannot be just
> called from any nesting level etc. etc.).
When you can *afford* a more "flush" environment, I agree that it
makes life a *lot* easier; you don't have to think about how many CPU
cycles you've burned since you last yield()-ed ("Am I starving some
task -- that I don't want to be aware of! -- that really NEEDS the
CPU more than me?"). You don't have to refactor the design as you add
tasks/complexity, etc.
You just concentrate on the individual "jobs" that need to be done.
But, what I'm attempting to show with my example is that you don't
have to make it an all-or-nothing decision; you can still avail
yourself of a multitasking environment (including other "services"
that a real OS would provide) even without all the resources that
you would otherwise ASSUME were needed!
Spaghetti code is never justified, IMO. Even tiny PICs can benefit
from more structured execution environments.
> If we really have to count the bytes of RAM - let us say we turn the
> clock 25 years back - we can statically assign as much stack as needed
> to each task. We may find out that splitting in 3 tasks can at
> times _save_ memory above a certain complexity...
>
> I thought we'd be done with counting for days every byte by now,
There are still a lot of designs that pinch pennies. The LORAN
plotter I mentioned ran in 12K of CODE and 256 bytes of RAM.
Back when 2716's were $50/each. We actually went through the
code to pull out a few hundred bytes by mapping the most frequent
subroutine CALL's (a 3 byte operation) to ReSTart instructions
(one byte SWI's, of a sort). Silly to put an extra $50 into the
device if it wasn't needed!
Nowadays, there's a lot of cruft added to many products that eats
up a lot of resources before you write your first byte of code.
E.g., communication stacks (ethernet, bluetooth, USB, etc.)
are now common whereas ages ago it was a hundred bytes to handle
a UART!
> last "small" MCU I used was a coldfire in tqfp100 with 16k RAM and
> a sort of 68000 running at 80 MHz.... I just copied and slightly
> adapted the initial (68340 from 1994) DPS scheduler and trap handler,
> cost me virtually nothing.
>
> http://tgi-sci.com/dsv/swgboard.gif
> http://tgi-sci.com/dsv/swg800.gif
Sheesh! Couldn't you have used a RULER to line up the mounting screws??
<grin>
> http://tgi-sci.com/misc/PICT6999.avi
> http://tgi-sci.com/tgi/auxhv.htm
> No picture of the last, this MCU replaced a huge computer board
> in an 8 channel Ortec alpha counting system so they could use
> two netmca-s to simultaneously select any two vacuum chhambers
> to count, measure the vacuum and plenty of other internals, the
> analog part was intact).
>
> And such an MCU costs well below $10 at Mouser or the likes for
> a single piece....
Yes, but there are complete products that *sell* for less than that!
E.g., I can buy a BT stereo headphone for $5 -- and a FEW people
in the distribution chain are making money on that! :-/ If
you are looking to create a "consumable" (disposable) product,
then you still *do* need to pinch pennies!
(My speech synthesizer has to fit *inside* something like that ALONGSIDE
its existing functionality and at a comparable price point)
OTOH, there are far too many fun/interesting things that are just not
practical to undertake when hobbled with a resource-starved environment.
And, once you get beyond a certain cost/complexity, the *added* costs
of moving to even richer execution environments is insignificant!
E.g., I recently doubled my clock speed (500M to 1G) and quadrupled
the number of cores in the design. And, its still laughably "cheap"!
[toc] | [prev] | [next] | [standalone]
| From | Les Cargill <lcargill99@comcast.com> |
|---|---|
| Date | 2016-06-29 11:36 -0500 |
| Message-ID | <nl0t75$3t5$1@dont-email.me> |
| In reply to | #24421 |
Dimiter_Popoff wrote: > On 28.6.2016 г. 17:40, Tim Wescott wrote: >> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote: >> >>> On 28.6.2016 г. 05:54, Simon Clubley wrote: >>>> >>> > ..... >>>> I still think that's a polling loop because you are reaching out to the >>>> sensor and asking it for it's current value. >>> >>> "Polling" in programming means "as opposed to interrupt handling". >>> How is this opposed to "interrupt handling". >>> >>> What you suggest to be polling is simply a loop of calls to subroutines. >>> A "call loop" is what describes it - although it does not matter a lot >>> what word is used as long as it is not an already widely accepted one >>> like "polling" which you want to redefine. Nothing wrong with that of >>> course - as long as you don't have to communicate with other people >>> using your redefined term. >>> >>> So much talk about so little :-). Although Tim's topic idea worked, >>> produced quite a discussion. >> >> Well, I was hoping for a name of a design pattern, and I'm still not >> happy about my choices. So from that perspective it's a wash. >> >> "Super loop" seems closest, but it seems to more capture the notion of >> _always_ executing A, B, C, rather than executing only those bits that >> are ready. >> > > I encounter the "super loop" term for the first time here, but why not. > Although I see nothing "super" about it, to me this is still an endless > loop of calls to subroutines either of which may opt to do something > or to just return if it has nothing to do. > But like I said earlier I have almost never used this approach, it > smells of oversimplifying - thus costing more than a decent scheduler > does. Implement loops, state machines etc. as you like within tasks > but having a true - preemptive allowing cooperative operation- scheduler > costs very little in both machine resources and effort to put together > so I see no point in trying to avoid it. > Other than for ISRs, you really don't *need* preemption. I once built a proto-RTOS on top of DOS whilst waiting for the hardware, back in the stone age. This allowed getting most of the work done. It was initially configured as cooperative multitasking. I put a task switch in the timer ISR and got that working. It made nothing particularly better nor worse. But of course, I had the thing working as a fully cooperative multitasker first. But the experience of doing that made me rather queasy about the very concept of preemption. Randomly yoinking the current task based on timer events seems a curious thing when you've A/B compared them. > Dimiter > > ------------------------------------------------------ > Dimiter Popoff, TGI http://www.tgi-sci.com > ------------------------------------------------------ > http://www.flickr.com/photos/didi_tgi/ > -- Les Cargill
[toc] | [prev] | [next] | [standalone]
| From | Don Y <blockedofcourse@foo.invalid> |
|---|---|
| Date | 2016-06-29 09:55 -0700 |
| Message-ID | <nl0ui8$8qv$1@dont-email.me> |
| In reply to | #24446 |
On 6/29/2016 9:36 AM, Les Cargill wrote:
> Dimiter_Popoff wrote:
>> On 28.6.2016 г. 17:40, Tim Wescott wrote:
>>> On Tue, 28 Jun 2016 06:20:43 +0300, Dimiter_Popoff wrote:
>>>
>>>> On 28.6.2016 г. 05:54, Simon Clubley wrote:
>>>>>
>>>> > .....
>>>>> I still think that's a polling loop because you are reaching out to the
>>>>> sensor and asking it for it's current value.
>>>>
>>>> "Polling" in programming means "as opposed to interrupt handling".
>>>> How is this opposed to "interrupt handling".
>>>>
>>>> What you suggest to be polling is simply a loop of calls to subroutines.
>>>> A "call loop" is what describes it - although it does not matter a lot
>>>> what word is used as long as it is not an already widely accepted one
>>>> like "polling" which you want to redefine. Nothing wrong with that of
>>>> course - as long as you don't have to communicate with other people
>>>> using your redefined term.
>>>>
>>>> So much talk about so little :-). Although Tim's topic idea worked,
>>>> produced quite a discussion.
>>>
>>> Well, I was hoping for a name of a design pattern, and I'm still not
>>> happy about my choices. So from that perspective it's a wash.
>>>
>>> "Super loop" seems closest, but it seems to more capture the notion of
>>> _always_ executing A, B, C, rather than executing only those bits that
>>> are ready.
>>>
>>
>> I encounter the "super loop" term for the first time here, but why not.
>> Although I see nothing "super" about it, to me this is still an endless
>> loop of calls to subroutines either of which may opt to do something
>> or to just return if it has nothing to do.
>> But like I said earlier I have almost never used this approach, it
>> smells of oversimplifying - thus costing more than a decent scheduler
>> does. Implement loops, state machines etc. as you like within tasks
>> but having a true - preemptive allowing cooperative operation- scheduler
>> costs very little in both machine resources and effort to put together
>> so I see no point in trying to avoid it.
>>
>
> Other than for ISRs, you really don't *need* preemption. I once built
> a proto-RTOS on top of DOS whilst waiting for the hardware, back
> in the stone age.
>
> This allowed getting most of the work done.
>
> It was initially configured as cooperative multitasking. I put a task switch in
> the timer ISR and got that working. It made nothing
> particularly better nor worse. But of course, I had the thing working
> as a fully cooperative multitasker first.
>
> But the experience of doing that made me rather queasy about the very concept
> of preemption. Randomly yoinking the current task based on
> timer events seems a curious thing when you've A/B compared them.
Preemption isn't just "a timer interrupt" but, rather, anything that
causes "something more important" to be invoked (scheduled) instead
of the currently executing task.
I.e., an ISR is a preemptive task.
An ISR can signal an event (or other OS-involved mechanism) that, in
turn, causes something that might be blocking, currently, to begin
execution -- without waiting for the currently executing task to
decide when an appropriate time to yield the processor might be.
[Should the executing task *poll* the event flag mentioned above to
decide when some other task is probably ready and waiting for THAT event?
Should each task know the needs of other concurrent tasks??]
The advantage of preemption is that tasks *don't* have to be considerate
of the needs of other tasks -- unlike the MTX I illustrated, here, which
must be *obsessed* with the needs of other tasks!
A fully preemptive MTOS typically also exploits EVERY possibility of
rerunning the scheduler, not just at jiffy's. E.g., if a task adjusts
its priority downward, a reschedule() should occur (because some other
higher priority task may be waiting to run and prohibited from doing
so solely by the previously higher priority of the currently
executing task.
Note that preemption can also extend *into* the kernel -- whereby the
kernel itself can be preempted (by other aspects of itself).
Developing under a preemptive MTOS requires a different discipline;
as does developing under a cooperative MTOS. For projects of substance,
it is usually too difficult to obtain maximum performance from a system
if you are charged with manually yielding control -- the system's
complexity makes it impractical for you to keep track of everything that
*might* be happening ("where *might* task32 be in its execution, now?")
[Again, that's why the MTX I've illustrated keeps the context switch
costs so lightweight; so you aren't concerned about yielding *often*
and gratuitously]
[toc] | [prev] | [next] | [standalone]
Page 4 of 10 — ← Prev page 1 2 3 [4] 5 6 … 10 Next page →
Back to top | Article view | comp.arch.embedded
csiph-web