Libuv and libuv

Source: Internet
Author: User

Libuv and libuv

Libuv is the basic library used by node. js, mainly including the main loop, file and network interface. Although libuv is born for node. js, it is an independent library and is easy to use. Therefore, many people outside node. js are using libuv. Several problems were found when libuv was integrated into V8 recently:

1. uv_fs-related functions cannot return the context information required by the calling function (such as the read buffer). They can only store data through global variables (global variables are used in the official example ). All functions related to uv_fs can provide a callback function. If the callback function is not empty, the current call is automatically converted into an asynchronous call, And the provided callback function is called upon completion of the operation. Generally, a callback function requires a variable as its context (providing parameters or saving results). The context of the function related to file operations is the uv_fs_t structure, however, the additional information provided by the caller cannot be saved.

uv_fs_t open_req;uv_fs_t read_req;uv_fs_t write_req;static char buffer[1024];static uv_buf_t iov;...void on_read(uv_fs_t *req) {    if (req->result < 0) {        fprintf(stderr, "Read error: %s\n", uv_strerror(req->result));    }    else if (req->result == 0) {        uv_fs_t close_req;        // synchronous        uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL);    }    else if (req->result > 0) {        iov.len = req->result;        uv_fs_write(uv_default_loop(), &write_req, 1, &iov, 1, -1, on_write);    }}void on_open(uv_fs_t *req) {    // The request passed to the callback is the same as the one the call setup    // function was passed.    assert(req == &open_req);    if (req->result >= 0) {        iov = uv_buf_init(buffer, sizeof(buffer));        uv_fs_read(uv_default_loop(), &read_req, req->result,                   &iov, 1, -1, on_read);    }    else {        fprintf(stderr, "error opening file: %s\n", uv_strerror((int)req->result));    }}...uv_fs_open(uv_default_loop(), &open_req, argv[1], O_RDONLY, 0, on_open);

I started to think that the data member is the place where the user data is stored. The buffer is passed through the data, but the data is always cleared. I can see the code in it that the data is used internally in fs. The official examples above are all passed through global variables, which is really abnormal!

2. Other threads cannot access the default main loop. Recently let the cantk-runtime-v8 support Touch/Key events encountered this problem: Touch/Key events are in the UI thread, while V8 is in the GLSurfaceView Render thread, calling JS in V8 directly through JNI will cause program crash, so I want to serialize the program through uv_idle, but the result is that the program still crashes. I remember that the idle in glib loop allows multi-thread access. When designing the main loop of FTK, I also use a pipe to serialize multiple threads to access the main loop, I thought that all the loop should support multithreading. I knew it only after reading the code. It didn't lock or use pipe for serialization:

  int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) {           \    if (uv__is_active(handle)) return 0;                                      \    if (cb == NULL) return -EINVAL;                                           \    QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue);         \    handle->name##_cb = cb;                                                   \    uv__handle_start(handle);                                                 \    return 0;                                                                 \  }    

3. uv_async cannot transmit data. I can't use uv_idle. I decided to use uv_async. This is not a crash, and the event seems to have been received, but the reaction in the game is a little weird. After carefully analyzing the LOG information, we found that touchmove and touchend received, but did not receive touchstart. Obviously, uv_async_send is executed. Why didn't the main loop handle this event? Continue to read the code:

void uv__async_send(struct uv__async* wa) {  const void* buf;  ssize_t len;  int fd;  int r;  buf = "";  len = 1;  fd = wa->wfd;#if defined(__linux__)  if (fd == -1) {    static const uint64_t val = 1;    buf = &val;    len = sizeof(val);    fd = wa->io_watcher.fd;  /* eventfd */  }#endif  do    r = write(fd, buf, len);  while (r == -1 && errno == EINTR);  if (r == len)    return;  if (r == -1)    if (errno == EAGAIN || errno == EWOULDBLOCK)      return;  abort();}

Async_send is executed synchronously. The above Code does not show any problems. Let's look at the acceptance section:

static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {  struct uv__async* wa;  char buf[1024];  unsigned n;  ssize_t r;  n = 0;  for (;;) {    r = read(w->fd, buf, sizeof(buf));    if (r > 0)      n += r;    if (r == sizeof(buf))      continue;    if (r != -1)      break;    if (errno == EAGAIN || errno == EWOULDBLOCK)      break;    if (errno == EINTR)      continue;    abort();  }  wa = container_of(w, struct uv__async, io_watcher);#if defined(__linux__)  if (wa->wfd == -1) {    uint64_t val;    assert(n == sizeof(val));    memcpy(&val, buf, sizeof(val));  /* Avoid alignment issues. */    wa->cb(loop, wa, val);    return;  }#endif  wa->cb(loop, wa, n);}

All the data is read, but the callback is called at the end. Even more depressing is that my understanding of async is wrong: the data member in uv_async_t cannot be used to transmit data. It is shared without protection between the two threads. The following code is an official example. This method can be used for low-speed communication, and later data will automatically overwrite the previous data, so touchstart will be overwritten and lost by touchmove.

void fake_download(uv_work_t *req) {    int size = *((int*) req->data);    int downloaded = 0;    double percentage;    while (downloaded < size) {        percentage = downloaded*100.0/size;        async.data = (void*) &percentage;        uv_async_send(&async);        sleep(1);        downloaded += (200+random())%1000; // can only download max 1000bytes/sec,                                           // but at least a 200;    }}

These problems are not a problem in node. js, but you must be careful when using libuv independently.

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.