[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Re: [PATCH V3] libxl, Introduce a QMP client
On Wed, 2011-06-15 at 19:44 +0100, Anthony PERARD wrote: > On Wed, Jun 15, 2011 at 11:04, Ian Campbell <Ian.Campbell@xxxxxxxxxxxxx> > wrote: > > On Tue, 2011-06-14 at 18:15 +0100, Anthony Perard wrote: > >> From: Anthony PERARD <anthony.perard@xxxxxxxxxx> > >> > >> QMP stands for QEMU Monitor Protocol and it is used to query information > >> from QEMU or to control QEMU. > >> > >> This implementation will ask QEMU the list of chardevice and store the > >> path to serial0 in xenstored. So we will be able to use xl console with > >> QEMU upstream. > >> > >> In order to connect to the QMP server, a socket file is created in > >> /var/run/xen/qmp-$(domid). > >> > >> Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> > >> --- > >> > >> Change v2->v3: > >> - Use of a timeout when wait for a reply from the server. > >> - Use of a command list, a list of pair "command" + callback. It's > >> associated > >> with an enum. > >> - Introduce libxl__qmp_initializations that will ask of all informations > >> need > >> through QMP. (It's just a rename of libxl__qmp_get_serial_console_path > >> from > >> the previous patch.) > > > > I would have sworn that initiali[zs]ations wasn't the plural of > > initiali[zs]e (it sounds wrong to my ear) and that it was one of those > > words with the same plural and singular form, but the Internet tells me > > I'm wrong... > > > > On the other hand libxl__qmp_domain_create works, so would something > > like libxl__qmp_gather_initial_info, the later conveys what's actually > > going on too... > > Actually, we could also set up the VNC password by this way. So in > this case, it will not be anymore only "gather initial info". Sure. In which case libxl__qmp_domain_create (or _setup) works. > >> @@ -245,6 +245,12 @@ static char ** > >> libxl__build_device_model_args_new(libxl__gc *gc, > >> flexarray_vappend(dm_args, dm, > >> "-xen-domid", libxl__sprintf(gc, "%d", > >> info->domid), NULL); > >> > >> + flexarray_append(dm_args, "-qmp"); > >> + flexarray_append(dm_args, > >> + libxl__sprintf(gc, "unix:%s/qmp-%d,server,nowait", > >> + libxl_run_dir_path(), > >> + info->domid)); > > > > Presumably qemu will clean this socket up in the normal shutdown case. > > Do we need to do so as well to handle crashes and the like? > > Actually, qemu doesn't remove the socket. So we will have do clean it > when the domain is cleaned. Is libxl_domain_destroy() a good function > to do that? I think so. There must be a function somewhere which signals qemu to shutdown (right?) -- I guess that be a good place? > >> + if (errno == ENOENT || errno == ECONNREFUSED) { > >> + /* ENOENT : Socket may not have shown up yet > >> + * ECONNREFUSED : Leftover socket hasn't been removed yet */ > >> + continue; > >> + } > >> + return -1; > >> + } while ((++i <= timeout * 5) && (usleep(.2 * 1000000) <= 0)); > > > > usleep (effectively) takes an unsigned int, what typedoes .2 * x become? > > It should be a float. But have 0.2 * 10^6 will be better to understand > that we have 0.2 second of sleep, but not power in C. If you prefere, > I will just wrote 200000, should be OK. My concern was just the floating * int multiplication going into a function which takes an int. I'm sure it all works out through the up- and down-casting and constant propagation etc and turns into the right thing, I just wondered if we could avoid it and make things clearer at the same time. > >> +#ifdef DEBUG_RECEIVE > >> + qmp->buffer[rd] = 0; > >> + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "received: '%s'", qmp->buffer); > >> +#endif > >> + > >> + while (bytes_parsed < rd) { > > [...] > >> + /* skip the CRLF of the end of a command */ > >> + while (bytes_parsed < rd && (qmp->buffer[bytes_parsed] == > >> '\r' > >> + || qmp->buffer[bytes_parsed] == > >> '\n')) { > >> + bytes_parsed++; > >> + } > > > > The parser doesn't just eat \r & \n? > > It does not eat it when it finished to parse a response but it will > eat these after. So the loop do another round and end up with a > partiel json data and an allocated parser. > > This little loop is just here to avoid doing a not necessary turn but > is not necessary It seems worthwhile then. > > [...] > >> +static int qmp_send(libxl__qmp_handler *qmp, const char *cmd, > >> qmp_callback_t callback) > >> +{ > >> + yajl_gen_config conf = { 0, NULL }; > >> + const unsigned char *buf; > >> + const char *ex = "execute"; > >> + unsigned int len = 0; > >> + yajl_gen_status s; > >> + yajl_gen hand; > >> + > >> + hand = yajl_gen_alloc(&conf, NULL); > >> + if (!hand) { > >> + return -1; > >> + } > >> + > >> + yajl_gen_map_open(hand); > >> + yajl_gen_string(hand, (const unsigned char *)ex, strlen(ex)); > >> + yajl_gen_string(hand, (const unsigned char *)cmd, strlen(cmd)); > >> + yajl_gen_string(hand, (const unsigned char *)"id", 2); > > > > ex is a variable and "id" is not? > > Well, it was easier to cound the char in "id" than in "execute", that > why there is a ex variable. But I think the next step would to eithier > use a #define QMP_{EXECUTE,ID} or a static const char* global to the > file. > > > You'd think yajl would have yajl_gen_asciiz or something. > > Unfortunatly, there is no such thing, at least in the debian version > (1.?). I did not check the 2.? version of libyajl. Perhaps we should have our own little helper function/macro which does this? > >> + yajl_gen_integer(hand, ++qmp->last_id_used); > >> + yajl_gen_map_close(hand); > >> + > >> + s = yajl_gen_get_buf(hand, &buf, &len); > >> + > >> + if (s) { > >> + LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, > >> + "could not generate a qmp command"); > >> + return -1; > >> + } > >> + > >> + if (callback) { > >> + callback_id_pair *elm = malloc(sizeof (callback_id_pair)); > >> + elm->id = qmp->last_id_used; > >> + elm->callback = callback; > >> + SIMPLEQ_INSERT_TAIL(&qmp->callback_list, elm, next); > >> + } > >> + > >> + LIBXL__LOG(qmp->ctx, LIBXL__LOG_DEBUG, "next qmp command: '%s'", buf); > >> + > >> + write(qmp->qmp_fd, buf, len); > >> + write(qmp->qmp_fd, "\r\n", 2); > > > > These need to handle partial writes? > > What did you mean ? > Call write twice was easier here than call a snprintf or other. I meant handling of write() returning < len or EINTR, EAGAIN etc. > Thanks for the review, No problem! Ian. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |