xiaoxiang781216 commented on code in PR #20723:
URL: https://github.com/apache/nuttx/pull/20723#discussion_r4316617134
##########
include/nuttx/tls.h:
##########
@@ -381,6 +382,19 @@ FAR struct tls_info_s *tls_get_info(void);
void tls_destruct(void);
#endif
+/****************************************************************************
+ * Name: __emutls_get_address and __emutls_register_common
+ *
+ * Description:
+ * The emulated TLS functions that GCC calls for __thread variables when
+ * the target has no native TLS. libc keeps one copy per thread.
+ *
+ ****************************************************************************/
+
+FAR void *__emutls_get_address(FAR void *arg);
+void __emutls_register_common(FAR void *arg, size_t size, size_t align,
Review Comment:
why need declared the compiler special functions
##########
arch/arm64/include/arch.h:
##########
@@ -57,6 +57,14 @@
#define UP_WFE() __asm__ __volatile__ ("wfe" : : : "memory")
#define UP_SEV() __asm__ __volatile__ ("sev" : : : "memory")
+/* The kernel keeps the address of the running thread's TLS info in
+ * TPIDR_EL0, so user code finds it whatever stack it runs on.
+ */
+
+#if !defined(__ASSEMBLY__) && !defined(__KERNEL__)
+# define up_tls_info() ((FAR struct tls_info_s *)read_sysreg(tpidr_el0))
Review Comment:
remove FAR in arch/arm64
##########
tools/Config.mk:
##########
@@ -895,3 +895,13 @@ LOWER_CASE = $(call ULMAP,$(LOWERMAP),$(1))
ifeq ($(CONFIG_ITERABLE_SECTIONS_LINKER_INSERT),y)
ARCHSCRIPT +=
$(TOPDIR)$(DELIM)include$(DELIM)nuttx$(DELIM)linker$(DELIM)common-insert.ld
endif
+
+# Take __emutls_get_address() from libc, which keeps a copy of a __thread
+# variable per thread, and not from libgcc: the apps of a flat image refer to
+# it only after the linker has scanned libc. The sim has native TLS.
+
+ifeq ($(CONFIG_BUILD_FLAT)$(CONFIG_ARCH_TOOLCHAIN_GCC),yy)
+ifneq ($(CONFIG_ARCH_SIM),y)
+ LDFLAGS += -u __emutls_get_address -u __emutls_register_common
Review Comment:
ditto
##########
libs/libc/tls/tls_getinfo.c:
##########
@@ -32,6 +32,16 @@
#include <nuttx/tls.h>
#include <nuttx/sched.h>
+#include "libc.h"
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* tls_emutls.c sets it on its first use, so exit() does not link it */
+
+CODE void (*g_tls_emutls_destruct)(void);
Review Comment:
why not declare tls_emutls_destruct weak?
##########
libs/libc/tls/tls_emutls.c:
##########
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * libs/libc/tls/tls_emutls.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/mutex.h>
+#include <nuttx/tls.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The control object that GCC emits for a __thread variable when the
+ * target has no native TLS, as defined by libgcc's emutls.c.
+ */
+
+struct __emutls_object
+{
+ size_t size;
+ size_t align;
+ union
+ {
+ uintptr_t offset;
+ FAR void *ptr;
+ } loc;
+ FAR void *templ;
+};
+
+/* The copies of the variables that one thread has used. The TLS info of
+ * the thread points to it.
+ */
+
+struct emutls_array_s
+{
+ uintptr_t size;
+ FAR void *data[1];
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The index of a variable is global: in a flat build all task groups share
+ * this data, but each variable has its own index.
+ */
+
+static mutex_t g_emutls_lock = NXMUTEX_INITIALIZER;
+static uintptr_t g_emutls_count;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: emutls_alloc
+ *
+ * Description:
+ * Allocate the copy of a variable for the calling thread, initialized
+ * from the template of the variable, or zeroed if it has none.
+ *
+ ****************************************************************************/
+
+static FAR void *emutls_alloc(FAR struct __emutls_object *obj)
+{
+ size_t align = obj->align > sizeof(FAR void *) ?
+ obj->align : sizeof(FAR void *);
+ FAR void *ptr;
+
+ ptr = lib_memalign(align, obj->size);
+ if (ptr == NULL)
+ {
+ abort();
+ }
+
+ if (obj->templ != NULL)
+ {
+ memcpy(ptr, obj->templ, obj->size);
+ }
+ else
+ {
+ memset(ptr, 0, obj->size);
+ }
+
+ return ptr;
+}
+
+/****************************************************************************
+ * Name: emutls_getarray
+ *
+ * Description:
+ * Return the array of the calling thread, large enough for index.
+ *
+ ****************************************************************************/
+
+static FAR struct emutls_array_s *
+emutls_getarray(FAR struct tls_info_s *tls, uintptr_t index)
+{
+ FAR struct emutls_array_s *array = tls->tl_emutls;
+ FAR struct emutls_array_s *newarray;
+ uintptr_t oldsize = array != NULL ? array->size : 0;
+ uintptr_t newsize;
+
+ if (index <= oldsize)
+ {
+ return array;
+ }
+
+ newsize = index + 16;
+ newarray = lib_realloc(array, sizeof(struct emutls_array_s) +
+ (newsize - 1) * sizeof(FAR void *));
+ if (newarray == NULL)
+ {
+ abort();
+ }
+
+ memset(&newarray->data[oldsize], 0,
+ (newsize - oldsize) * sizeof(FAR void *));
+ newarray->size = newsize;
+ tls->tl_emutls = newarray;
+ g_tls_emutls_destruct = tls_emutls_destruct;
+ return newarray;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: __emutls_get_address
+ *
+ * Description:
+ * Return the address of the calling thread's copy of a __thread
+ * variable. It replaces libgcc's version, which keeps a single copy
+ * when libgcc is built without thread support. GCC declares it as a
+ * builtin with a void pointer argument.
+ *
+ ****************************************************************************/
+
+FAR void *__emutls_get_address(FAR void *arg)
+{
+ FAR struct __emutls_object *obj = arg;
+ FAR struct emutls_array_s *array;
+ uintptr_t index;
+
+ index = __atomic_load_n(&obj->loc.offset, __ATOMIC_ACQUIRE);
+ if (index == 0)
+ {
+ nxmutex_lock(&g_emutls_lock);
+ index = obj->loc.offset;
+ if (index == 0)
+ {
+ index = ++g_emutls_count;
+ __atomic_store_n(&obj->loc.offset, index, __ATOMIC_RELEASE);
+ }
+
+ nxmutex_unlock(&g_emutls_lock);
+ }
+
+ array = emutls_getarray(tls_get_info(), index);
Review Comment:
let's --index to simplify the follow code
##########
libs/libc/tls/tls_emutls.c:
##########
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * libs/libc/tls/tls_emutls.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/mutex.h>
+#include <nuttx/tls.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The control object that GCC emits for a __thread variable when the
+ * target has no native TLS, as defined by libgcc's emutls.c.
+ */
+
+struct __emutls_object
+{
+ size_t size;
+ size_t align;
+ union
+ {
+ uintptr_t offset;
+ FAR void *ptr;
+ } loc;
+ FAR void *templ;
+};
+
+/* The copies of the variables that one thread has used. The TLS info of
+ * the thread points to it.
+ */
+
+struct emutls_array_s
+{
+ uintptr_t size;
+ FAR void *data[1];
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The index of a variable is global: in a flat build all task groups share
+ * this data, but each variable has its own index.
+ */
+
+static mutex_t g_emutls_lock = NXMUTEX_INITIALIZER;
+static uintptr_t g_emutls_count;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: emutls_alloc
+ *
+ * Description:
+ * Allocate the copy of a variable for the calling thread, initialized
+ * from the template of the variable, or zeroed if it has none.
+ *
+ ****************************************************************************/
+
+static FAR void *emutls_alloc(FAR struct __emutls_object *obj)
+{
+ size_t align = obj->align > sizeof(FAR void *) ?
+ obj->align : sizeof(FAR void *);
+ FAR void *ptr;
+
+ ptr = lib_memalign(align, obj->size);
+ if (ptr == NULL)
+ {
+ abort();
+ }
+
+ if (obj->templ != NULL)
+ {
+ memcpy(ptr, obj->templ, obj->size);
+ }
+ else
+ {
+ memset(ptr, 0, obj->size);
+ }
+
+ return ptr;
+}
+
+/****************************************************************************
+ * Name: emutls_getarray
+ *
+ * Description:
+ * Return the array of the calling thread, large enough for index.
+ *
+ ****************************************************************************/
+
+static FAR struct emutls_array_s *
+emutls_getarray(FAR struct tls_info_s *tls, uintptr_t index)
+{
+ FAR struct emutls_array_s *array = tls->tl_emutls;
+ FAR struct emutls_array_s *newarray;
+ uintptr_t oldsize = array != NULL ? array->size : 0;
+ uintptr_t newsize;
+
+ if (index <= oldsize)
Review Comment:
`index < oldsize`
##########
libs/libc/tls/CMakeLists.txt:
##########
@@ -20,7 +20,20 @@
#
#
##############################################################################
-set(SRCS task_getinfo.c tls_getinfo.c)
+set(SRCS task_getinfo.c tls_getinfo.c tls_emutls.c)
+
+# Take the emutls functions from libc, not from libgcc: the apps refer to them
+# only after the linker has scanned libc (see tools/Config.mk).
+
+if(CONFIG_ARCH_TOOLCHAIN_GCC AND NOT CONFIG_ARCH_SIM)
+ set(EMUTLS_LDFLAGS "SHELL:-u __emutls_get_address"
Review Comment:
let's use wrap to avoid linking the symbol provided libgcc
##########
libs/libc/tls/CMakeLists.txt:
##########
@@ -20,7 +20,20 @@
#
#
##############################################################################
-set(SRCS task_getinfo.c tls_getinfo.c)
+set(SRCS task_getinfo.c tls_getinfo.c tls_emutls.c)
+
+# Take the emutls functions from libc, not from libgcc: the apps refer to them
+# only after the linker has scanned libc (see tools/Config.mk).
+
+if(CONFIG_ARCH_TOOLCHAIN_GCC AND NOT CONFIG_ARCH_SIM)
Review Comment:
why skip CONFIG_ARCH_SIM
##########
libs/libc/libc.h:
##########
@@ -332,6 +332,13 @@ ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct
hostent *host,
int lib_restoredir(void);
#endif
+/* Defined in tls/tls_emutls.c. exit() and pthread_exit() call
+ * tls_emutls_destruct() through g_tls_emutls_destruct (tls/tls_getinfo.c).
+ */
+
+extern CODE void (*g_tls_emutls_destruct)(void);
Review Comment:
why not call tls_emutls_destruct directly
##########
libs/libc/tls/tls_emutls.c:
##########
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * libs/libc/tls/tls_emutls.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/mutex.h>
+#include <nuttx/tls.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The control object that GCC emits for a __thread variable when the
+ * target has no native TLS, as defined by libgcc's emutls.c.
+ */
+
+struct __emutls_object
+{
+ size_t size;
+ size_t align;
+ union
+ {
+ uintptr_t offset;
+ FAR void *ptr;
+ } loc;
+ FAR void *templ;
+};
+
+/* The copies of the variables that one thread has used. The TLS info of
+ * the thread points to it.
+ */
+
+struct emutls_array_s
+{
+ uintptr_t size;
+ FAR void *data[1];
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The index of a variable is global: in a flat build all task groups share
+ * this data, but each variable has its own index.
+ */
+
+static mutex_t g_emutls_lock = NXMUTEX_INITIALIZER;
+static uintptr_t g_emutls_count;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: emutls_alloc
+ *
+ * Description:
+ * Allocate the copy of a variable for the calling thread, initialized
+ * from the template of the variable, or zeroed if it has none.
+ *
+ ****************************************************************************/
+
+static FAR void *emutls_alloc(FAR struct __emutls_object *obj)
+{
+ size_t align = obj->align > sizeof(FAR void *) ?
+ obj->align : sizeof(FAR void *);
+ FAR void *ptr;
+
+ ptr = lib_memalign(align, obj->size);
+ if (ptr == NULL)
+ {
+ abort();
+ }
+
+ if (obj->templ != NULL)
+ {
+ memcpy(ptr, obj->templ, obj->size);
+ }
+ else
+ {
+ memset(ptr, 0, obj->size);
+ }
+
+ return ptr;
+}
+
+/****************************************************************************
+ * Name: emutls_getarray
+ *
+ * Description:
+ * Return the array of the calling thread, large enough for index.
+ *
+ ****************************************************************************/
+
+static FAR struct emutls_array_s *
+emutls_getarray(FAR struct tls_info_s *tls, uintptr_t index)
+{
+ FAR struct emutls_array_s *array = tls->tl_emutls;
+ FAR struct emutls_array_s *newarray;
+ uintptr_t oldsize = array != NULL ? array->size : 0;
+ uintptr_t newsize;
+
+ if (index <= oldsize)
+ {
+ return array;
+ }
+
+ newsize = index + 16;
+ newarray = lib_realloc(array, sizeof(struct emutls_array_s) +
+ (newsize - 1) * sizeof(FAR void *));
+ if (newarray == NULL)
+ {
+ abort();
+ }
+
+ memset(&newarray->data[oldsize], 0,
+ (newsize - oldsize) * sizeof(FAR void *));
+ newarray->size = newsize;
+ tls->tl_emutls = newarray;
+ g_tls_emutls_destruct = tls_emutls_destruct;
+ return newarray;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: __emutls_get_address
+ *
+ * Description:
+ * Return the address of the calling thread's copy of a __thread
+ * variable. It replaces libgcc's version, which keeps a single copy
+ * when libgcc is built without thread support. GCC declares it as a
+ * builtin with a void pointer argument.
+ *
+ ****************************************************************************/
+
+FAR void *__emutls_get_address(FAR void *arg)
+{
+ FAR struct __emutls_object *obj = arg;
+ FAR struct emutls_array_s *array;
+ uintptr_t index;
+
+ index = __atomic_load_n(&obj->loc.offset, __ATOMIC_ACQUIRE);
Review Comment:
why not call function defined in nutttx/atomic.h
##########
libs/libc/tls/tls_emutls.c:
##########
@@ -0,0 +1,254 @@
+/****************************************************************************
+ * libs/libc/tls/tls_emutls.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nuttx/mutex.h>
+#include <nuttx/tls.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The control object that GCC emits for a __thread variable when the
+ * target has no native TLS, as defined by libgcc's emutls.c.
+ */
+
+struct __emutls_object
+{
+ size_t size;
+ size_t align;
+ union
+ {
+ uintptr_t offset;
+ FAR void *ptr;
+ } loc;
+ FAR void *templ;
+};
+
+/* The copies of the variables that one thread has used. The TLS info of
+ * the thread points to it.
+ */
+
+struct emutls_array_s
+{
+ uintptr_t size;
+ FAR void *data[1];
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The index of a variable is global: in a flat build all task groups share
+ * this data, but each variable has its own index.
+ */
+
+static mutex_t g_emutls_lock = NXMUTEX_INITIALIZER;
+static uintptr_t g_emutls_count;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: emutls_alloc
+ *
+ * Description:
+ * Allocate the copy of a variable for the calling thread, initialized
+ * from the template of the variable, or zeroed if it has none.
+ *
+ ****************************************************************************/
+
+static FAR void *emutls_alloc(FAR struct __emutls_object *obj)
+{
+ size_t align = obj->align > sizeof(FAR void *) ?
+ obj->align : sizeof(FAR void *);
+ FAR void *ptr;
+
+ ptr = lib_memalign(align, obj->size);
+ if (ptr == NULL)
+ {
+ abort();
+ }
+
+ if (obj->templ != NULL)
+ {
+ memcpy(ptr, obj->templ, obj->size);
+ }
+ else
+ {
+ memset(ptr, 0, obj->size);
+ }
+
+ return ptr;
+}
+
+/****************************************************************************
+ * Name: emutls_getarray
+ *
+ * Description:
+ * Return the array of the calling thread, large enough for index.
+ *
+ ****************************************************************************/
+
+static FAR struct emutls_array_s *
+emutls_getarray(FAR struct tls_info_s *tls, uintptr_t index)
+{
+ FAR struct emutls_array_s *array = tls->tl_emutls;
+ FAR struct emutls_array_s *newarray;
+ uintptr_t oldsize = array != NULL ? array->size : 0;
+ uintptr_t newsize;
+
+ if (index <= oldsize)
+ {
+ return array;
+ }
+
+ newsize = index + 16;
+ newarray = lib_realloc(array, sizeof(struct emutls_array_s) +
+ (newsize - 1) * sizeof(FAR void *));
+ if (newarray == NULL)
+ {
+ abort();
+ }
+
+ memset(&newarray->data[oldsize], 0,
+ (newsize - oldsize) * sizeof(FAR void *));
+ newarray->size = newsize;
+ tls->tl_emutls = newarray;
+ g_tls_emutls_destruct = tls_emutls_destruct;
+ return newarray;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: __emutls_get_address
+ *
+ * Description:
+ * Return the address of the calling thread's copy of a __thread
+ * variable. It replaces libgcc's version, which keeps a single copy
+ * when libgcc is built without thread support. GCC declares it as a
+ * builtin with a void pointer argument.
+ *
+ ****************************************************************************/
+
+FAR void *__emutls_get_address(FAR void *arg)
+{
+ FAR struct __emutls_object *obj = arg;
+ FAR struct emutls_array_s *array;
+ uintptr_t index;
+
+ index = __atomic_load_n(&obj->loc.offset, __ATOMIC_ACQUIRE);
+ if (index == 0)
+ {
+ nxmutex_lock(&g_emutls_lock);
+ index = obj->loc.offset;
+ if (index == 0)
+ {
+ index = ++g_emutls_count;
+ __atomic_store_n(&obj->loc.offset, index, __ATOMIC_RELEASE);
Review Comment:
ditto
##########
libs/libc/libc.h:
##########
@@ -332,12 +332,15 @@ ssize_t lib_parse_hostfile(FAR FILE *stream, FAR struct
hostent *host,
int lib_restoredir(void);
#endif
-/* Defined in tls/tls_emutls.c. exit() and pthread_exit() call
- * tls_emutls_destruct() through g_tls_emutls_destruct (tls/tls_getinfo.c).
+/* Defined in tls/tls_emutls.c. exit(), pthread_exit() and the loader call
+ * them through these pointers (tls/tls_getinfo.c).
*/
extern CODE void (*g_tls_emutls_destruct)(void);
+extern CODE void (*g_tls_emutls_release)(FAR const void *start,
Review Comment:
let's call lib_emutls_release directly
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]