diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-08-30 15:43:32 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2008-08-30 15:43:32 +0000 |
commit | 7cbb998f1479d9e8975cd3f1e5a98f3fffaa5670 (patch) | |
tree | 751094b8b61b72284b65b02886998faa7c365bf4 /nuttx/examples/nsh/nsh_telnetd.c | |
parent | 19730f2f20d3244c684ba0cfeffea25df8b5fe78 (diff) | |
download | px4-nuttx-7cbb998f1479d9e8975cd3f1e5a98f3fffaa5670.tar.gz px4-nuttx-7cbb998f1479d9e8975cd3f1e5a98f3fffaa5670.tar.bz2 px4-nuttx-7cbb998f1479d9e8975cd3f1e5a98f3fffaa5670.zip |
Use pthreads instead of tasks in BG
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@855 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/examples/nsh/nsh_telnetd.c')
-rw-r--r-- | nuttx/examples/nsh/nsh_telnetd.c | 165 |
1 files changed, 120 insertions, 45 deletions
diff --git a/nuttx/examples/nsh/nsh_telnetd.c b/nuttx/examples/nsh/nsh_telnetd.c index 5cfe7ba50..9699aa651 100644 --- a/nuttx/examples/nsh/nsh_telnetd.c +++ b/nuttx/examples/nsh/nsh_telnetd.c @@ -51,7 +51,9 @@ #include <stdarg.h> #include <string.h> #include <pthread.h> +#include <semaphore.h> #include <assert.h> +#include <errno.h> #include <debug.h> #include <net/if.h> @@ -59,6 +61,8 @@ #include "nsh.h" +#ifdef CONFIG_EXAMPLES_NSH_TELNET + /**************************************************************************** * Definitions ****************************************************************************/ @@ -86,10 +90,13 @@ struct telnetio_s { + sem_t tio_sem; + pid_t tio_holder; int tio_sockfd; uint16 tio_sndlen; uint8 tio_bufndx; uint8 tio_state; + uint8 tio_semnest; char tio_buffer[CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE]; }; @@ -113,7 +120,6 @@ struct telnetd_s { struct nsh_vtbl_s tn_vtbl; boolean tn_redirected; - int tn_refs; /* Reference counts on the instance */ union { struct telnetio_s *tn; @@ -127,7 +133,6 @@ struct telnetd_s ****************************************************************************/ static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl); -static void nsh_telnetaddref(FAR struct nsh_vtbl_s *vtbl); static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl); static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); @@ -141,6 +146,72 @@ static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl); ****************************************************************************/ /**************************************************************************** + * Name: tio_semtake + ****************************************************************************/ + +static void tio_semtake(struct telnetio_s *tio) +{ + pid_t my_pid = getpid(); + + /* Does this task already have the semaphore? */ + + if (tio->tio_holder == my_pid) + { + /* Yes, just increment the number of references that the task holds */ + + tio->tio_semnest++; + } + else + { + /* No, Take the semaphore (perhaps waiting) */ + + while (sem_wait(&tio->tio_sem) != 0) + { + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + ASSERT(errno == EINTR); + } + + /* Stake the claim and return */ + + tio->tio_holder = my_pid; + tio->tio_semnest = 1; + } +} + +/**************************************************************************** + * Name: tio_semgive + ****************************************************************************/ + +static void tio_semgive(struct telnetio_s *tio) +{ + pid_t my_pid = getpid(); + + /* I better be holding at least one count on the semaphore */ + + ASSERT(tio->tio_holder == my_pid); + + /* Do I hold multiple references to the semphore */ + + if (tio->tio_semnest > 1) + { + /* Yes, just release one count and return */ + + tio->tio_semnest--; + } + else + { + /* Nope, this is the last reference I have */ + + tio->tio_holder = -1; + tio->tio_semnest = 0; + ASSERT(sem_post(&tio->tio_sem) == 0); + } +} + +/**************************************************************************** * Name: nsh_dumpbuffer * * Description: @@ -196,22 +267,16 @@ static void nsh_dumpbuffer(const char *msg, const char *buffer, ssize_t nbytes) static FAR struct telnetd_s *nsh_allocstruct(void) { - struct telnetd_s *pstate = (struct telnetd_s *)malloc(sizeof(struct telnetd_s)); + struct telnetd_s *pstate = (struct telnetd_s *)zalloc(sizeof(struct telnetd_s)); if (pstate) { - memset(pstate, 0, sizeof(struct telnetd_s)); pstate->tn_vtbl.clone = nsh_telnetclone; - pstate->tn_vtbl.addref = nsh_telnetaddref; pstate->tn_vtbl.release = nsh_telnetrelease; pstate->tn_vtbl.output = nsh_telnetoutput; pstate->tn_vtbl.linebuffer = nsh_telnetlinebuffer; pstate->tn_vtbl.redirect = nsh_telnetredirect; pstate->tn_vtbl.undirect = nsh_telnetundirect; pstate->tn_vtbl.exit = nsh_telnetexit; - - memset(&pstate->tn_vtbl.np, 0, sizeof(struct nsh_parser_s)); - - pstate->tn_refs = 1; } return pstate; } @@ -275,6 +340,9 @@ static void nsh_closeifnotclosed(struct telnetd_s *pstate) * Description: * Add another parsed character to the TELNET command string * + * Assumption: + * Caller holds TIO semaphore + * ****************************************************************************/ static void nsh_putchar(struct telnetd_s *pstate, uint8 ch) @@ -327,7 +395,7 @@ static void nsh_sendopt(struct telnetd_s *pstate, uint8 option, uint8 value) nsh_dumpbuffer("Send optbuf", optbuf, 4); if (send(tio->tio_sockfd, optbuf, 4, 0) < 0) { - dbg("[%d] Failed to send TELNET_IAC\n", tio->tio_sockfd); + dbg("[%d] Failed to send TELNET_IAC: %d\n", tio->tio_sockfd, errno); } } @@ -343,15 +411,17 @@ static void nsh_flush(FAR struct telnetd_s *pstate) { struct telnetio_s *tio = pstate->u.tn; + tio_semtake(tio); if (tio->tio_sndlen > 0) { nsh_dumpbuffer("Shell output", tio->tio_buffer, tio->tio_sndlen); if (send(tio->tio_sockfd, tio->tio_buffer, tio->tio_sndlen, 0) < 0) { - dbg("[%d] Failed to send response\n", tio->tio_sockfd); + dbg("[%d] Failed to send response: %d\n", tio->tio_sockfd, errno); } } tio->tio_sndlen = 0; + tio_semgive(tio); } /**************************************************************************** @@ -368,6 +438,7 @@ static int nsh_receive(struct telnetd_s *pstate, size_t len) char *ptr = tio->tio_buffer; uint8 ch; + tio_semtake(tio); while (len > 0) { ch = *ptr++; @@ -449,6 +520,7 @@ static int nsh_receive(struct telnetd_s *pstate, size_t len) break; } } + tio_semgive(tio); return OK; } @@ -465,7 +537,7 @@ static int nsh_receive(struct telnetd_s *pstate, size_t len) static void *nsh_connection(void *arg) { struct telnetd_s *pstate = nsh_allocstruct(); - struct telnetio_s *tio = (struct telnetio_s *)malloc(sizeof(struct telnetio_s)); + struct telnetio_s *tio = (struct telnetio_s *)zalloc(sizeof(struct telnetio_s)); int sockfd = (int)arg; int ret = ERROR; @@ -477,7 +549,7 @@ static void *nsh_connection(void *arg) { /* Initialize the thread state structure */ - memset(tio, 0, sizeof(struct telnetio_s)); + sem_init(&tio->tio_sem, 0, 1); tio->tio_sockfd = sockfd; tio->tio_state = STATE_NORMAL; pstate->u.tn = tio; @@ -503,7 +575,7 @@ static void *nsh_connection(void *arg) /* Process the received TELNET data */ - nsh_dumpbuffer("Received buffer", pstate->u.tn.tio_buffer, ret); + nsh_dumpbuffer("Received buffer", tio->tio_buffer, ret); ret = nsh_receive(pstate, ret); } } @@ -522,6 +594,7 @@ static void *nsh_connection(void *arg) if (tio) { + sem_destroy(&tio->tio_sem); free(tio); } @@ -550,6 +623,8 @@ static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) int len; va_list ap; + tio_semtake(tio); + /* Put the new info into the buffer. Here we are counting on the fact that * no output strings will exceed CONFIG_EXAMPLES_NSH_LINELEN! */ @@ -582,6 +657,7 @@ static int nsh_telnetoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) * maximum length string. */ + tio_semgive(tio); if (nbytes > CONFIG_EXAMPLES_NSH_IOBUFFER_SIZE - CONFIG_EXAMPLES_NSH_LINELEN) { nsh_flush(pstate); @@ -613,11 +689,11 @@ static int nsh_redirectoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...) { return ERROR; } - + va_start(ap, fmt); ret = vfprintf(pstate->u.rd.rd_stream, fmt, ap); va_end(ap); - + return ret; } @@ -645,52 +721,49 @@ static FAR char *nsh_telnetlinebuffer(FAR struct nsh_vtbl_s *vtbl) static FAR struct nsh_vtbl_s *nsh_telnetclone(FAR struct nsh_vtbl_s *vtbl) { - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - FAR struct telnetd_s *pclone = nsh_allocstruct(); - - pclone->tn_redirected = TRUE; - pclone->tn_vtbl.output = nsh_redirectoutput; - pclone->u.rd.rd_fd = pstate->u.rd.rd_fd; - pclone->u.rd.rd_stream = NULL; - return &pclone->tn_vtbl; -} - -/**************************************************************************** - * Name: nsh_telnetaddref - * - * Description: - * Increment the reference count on the vtbl. - * - ****************************************************************************/ + FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; + FAR struct telnetd_s *pclone = nsh_allocstruct(); + FAR struct nsh_vtbl_s *ret = NULL; -static void nsh_telnetaddref(FAR struct nsh_vtbl_s *vtbl) -{ - FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - pstate->tn_refs++; + if (pclone) + { + if (pstate->tn_redirected) + { + pclone->tn_redirected = TRUE; + pclone->tn_vtbl.output = nsh_redirectoutput; + pclone->u.rd.rd_fd = pstate->u.rd.rd_fd; + pclone->u.rd.rd_stream = NULL; + } + else + { + pclone->u.tn = pstate->u.tn; + } + ret = &pclone->tn_vtbl; + } + return ret; } /**************************************************************************** * Name: nsh_telnetrelease * * Description: - * Decrement the reference count on the vtbl, releasing it when the count - * decrements to zero. + * Release the cloned instance * ****************************************************************************/ static void nsh_telnetrelease(FAR struct nsh_vtbl_s *vtbl) { FAR struct telnetd_s *pstate = (FAR struct telnetd_s *)vtbl; - if (pstate->tn_refs > 1) + + if (pstate->tn_redirected) { - pstate->tn_refs--; + nsh_closeifnotclosed(pstate); } else { - DEBUGASSERT(pstate->tn_redirected); - nsh_closeifnotclosed(pstate); - free(vtbl); + nsh_flush(pstate); } + free(pstate); } /**************************************************************************** @@ -768,7 +841,7 @@ static void nsh_telnetexit(FAR struct nsh_vtbl_s *vtbl) ****************************************************************************/ /**************************************************************************** - * Name: nsh_main + * Name: nsh_telnetmain * * Description: * This is the main processing thread for telnetd. It never returns @@ -857,3 +930,5 @@ int nsh_telnetmain(int argc, char *argv[]) uip_server(HTONS(23), nsh_connection, CONFIG_EXAMPLES_NSH_STACKSIZE); return OK; } + +#endif /* CONFIG_EXAMPLES_NSH_TELNET */ |